diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt index 2feb003928..96164c49c6 100644 --- a/android/CMakeLists.txt +++ b/android/CMakeLists.txt @@ -11,7 +11,7 @@ string(APPEND CMAKE_CXX_FLAGS " -DRCT_NEW_ARCH_ENABLED") set(ANDROID_CPP_DIR "${CMAKE_SOURCE_DIR}/src/main/cpp") set(COMMON_CPP_DIR "${CMAKE_SOURCE_DIR}/../common") -set(ET_LIB_DIR "${CMAKE_SOURCE_DIR}/../third-party/android/libs") -set(ET_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/../third-party/include") +set(LIBS_DIR "${CMAKE_SOURCE_DIR}/../third-party/android/libs") +set(INCLUDE_DIR "${CMAKE_SOURCE_DIR}/../third-party/include") add_subdirectory("${ANDROID_CPP_DIR}") \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 1dc3f045ae..7d4ed01c4f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -111,7 +111,7 @@ android { targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") externalNativeBuild { cmake { - cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all" + cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all -fopenmp -static-openmp" abiFilters (*reactNativeArchitectures()) arguments "-DANDROID_STL=c++_shared", "-DREACT_NATIVE_DIR=${toPlatformFileString(reactNativeRootDir.path)}" @@ -142,6 +142,7 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + } repositories { @@ -162,7 +163,7 @@ dependencies { implementation 'com.facebook.fbjni:fbjni:0.6.0' implementation 'org.opencv:opencv:4.10.0' implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation(files("../third-party/android/libs/executorch.aar")) + implementation(files("../third-party/android/libs/executorch/executorch.aar")) implementation 'org.opencv:opencv:4.10.0' implementation("com.squareup.okhttp3:okhttp:4.9.2") } diff --git a/android/src/main/cpp/CMakeLists.txt b/android/src/main/cpp/CMakeLists.txt index 83ce121343..901946bbaf 100644 --- a/android/src/main/cpp/CMakeLists.txt +++ b/android/src/main/cpp/CMakeLists.txt @@ -13,11 +13,10 @@ target_include_directories( PUBLIC "${COMMON_CPP_DIR}" "${ANDROID_CPP_DIR}" - "${ET_INCLUDE_DIR}" + "${INCLUDE_DIR}" "${REACT_NATIVE_DIR}/ReactCommon" "${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni/react/turbomodule" "${REACT_NATIVE_DIR}/ReactCommon/callinvoker" - "${BUILD_DIR}/generated/source/codegen/jni/react/renderer/components/RnExecutorchSpec" ) set(LINK_LIBRARIES @@ -31,14 +30,42 @@ set(RN_VERSION_LINK_LIBRARIES ReactAndroid::reactnative ) +# Dependencies: +# ------- Executorch ------- + add_library(executorch SHARED IMPORTED) set_target_properties(executorch PROPERTIES - IMPORTED_LOCATION "${ET_LIB_DIR}/${ANDROID_ABI}/libexecutorch.so") + IMPORTED_LOCATION "${LIBS_DIR}/executorch/${ANDROID_ABI}/libexecutorch.so") + +# ------- OpenCV ------- + +set(OPENCV_LIBS + "${LIBS_DIR}/opencv/${ANDROID_ABI}/libopencv_core.a" + "${LIBS_DIR}/opencv/${ANDROID_ABI}/libopencv_features2d.a" + "${LIBS_DIR}/opencv/${ANDROID_ABI}/libopencv_highgui.a" + "${LIBS_DIR}/opencv/${ANDROID_ABI}/libopencv_imgproc.a" + "${LIBS_DIR}/opencv/${ANDROID_ABI}/libopencv_photo.a" + "${LIBS_DIR}/opencv/${ANDROID_ABI}/libopencv_video.a" +) + +if(ANDROID_ABI STREQUAL "arm64-v8a") + set(OPENCV_THIRD_PARTY_LIBS + "${LIBS_DIR}/opencv-third-party/${ANDROID_ABI}/libkleidicv_hal.a" + "${LIBS_DIR}/opencv-third-party/${ANDROID_ABI}/libkleidicv_thread.a" + "${LIBS_DIR}/opencv-third-party/${ANDROID_ABI}/libkleidicv.a" + ) +elseif(ANDROID_ABI STREQUAL "x86_64") + set(OPENCV_THIRD_PARTY_LIBS "") +endif() + +# -------------- target_link_libraries( react-native-executorch ${LINK_LIBRARIES} ${RN_VERSION_LINK_LIBRARIES} + ${OPENCV_LIBS} + ${OPENCV_THIRD_PARTY_LIBS} executorch ) \ No newline at end of file diff --git a/android/src/main/cpp/ETInstallerModule.cpp b/android/src/main/cpp/ETInstallerModule.cpp index cec899bded..d69af8634b 100644 --- a/android/src/main/cpp/ETInstallerModule.cpp +++ b/android/src/main/cpp/ETInstallerModule.cpp @@ -1,8 +1,12 @@ #include "ETInstallerModule.h" -#include "RnExecutorchInstaller.h" -namespace rnexecutorch { +#include + +#include +#include +namespace rnexecutorch { +JavaVM *java_machine; using namespace facebook::jni; ETInstallerModule::ETInstallerModule( @@ -30,6 +34,43 @@ void ETInstallerModule::registerNatives() { } void ETInstallerModule::injectJSIBindings() { - RnExecutorchInstaller::injectJSIBindings(jsiRuntime_, jsCallInvoker_); + // Grab a function for fetching images via URL from Java + auto fetchDataByUrl = [](std::string url) { + // Attaching Current Thread to JVM + + JNIEnv *env = nullptr; + int getEnvStat = java_machine->GetEnv((void **)&env, JNI_VERSION_1_6); + if (getEnvStat == JNI_EDETACHED) { + if (java_machine->AttachCurrentThread(&env, nullptr) != 0) { + throw std::runtime_error("Failed to attach thread to JVM"); + } + } + static jclass cls = javaClassStatic().get(); + static jmethodID method = env->GetStaticMethodID( + cls, "fetchByteDataFromUrl", "(Ljava/lang/String;)[B"); + + jstring jUrl = env->NewStringUTF(url.c_str()); + jbyteArray byteData = + (jbyteArray)env->CallStaticObjectMethod(cls, method, jUrl); + + if (env->IsSameObject(byteData, NULL)) { + throw std::runtime_error("Error fetching data from a url"); + } + + int size = env->GetArrayLength(byteData); + jbyte *bytes = env->GetByteArrayElements(byteData, JNI_FALSE); + std::byte *dataBytePtr = reinterpret_cast(bytes); + + return std::vector(dataBytePtr, dataBytePtr + size); + }; + + RnExecutorchInstaller::injectJSIBindings(jsiRuntime_, jsCallInvoker_, + fetchDataByUrl); } -} // namespace rnexecutorch \ No newline at end of file +} // namespace rnexecutorch + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + rnexecutorch::java_machine = vm; + return facebook::jni::initialize( + vm, [] { rnexecutorch::ETInstallerModule::registerNatives(); }); +} \ No newline at end of file diff --git a/android/src/main/cpp/OnLoad.cpp b/android/src/main/cpp/OnLoad.cpp deleted file mode 100644 index dedb387119..0000000000 --- a/android/src/main/cpp/OnLoad.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include - -#include - -using namespace rnexecutorch; - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - return facebook::jni::initialize( - vm, [] { ETInstallerModule::registerNatives(); }); -} \ No newline at end of file diff --git a/android/src/main/java/com/swmansion/rnexecutorch/ETInstaller.kt b/android/src/main/java/com/swmansion/rnexecutorch/ETInstaller.kt index 51d4e9fc5e..acc43c0a9e 100644 --- a/android/src/main/java/com/swmansion/rnexecutorch/ETInstaller.kt +++ b/android/src/main/java/com/swmansion/rnexecutorch/ETInstaller.kt @@ -1,11 +1,14 @@ package com.swmansion.rnexecutorch import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactMethod import com.facebook.react.common.annotations.FrameworkAPI import com.facebook.react.module.annotations.ReactModule import com.facebook.react.turbomodule.core.CallInvokerHolderImpl +import java.io.InputStream +import java.net.URL @OptIn(FrameworkAPI::class) @ReactModule(name = ETInstaller.NAME) @@ -14,6 +17,25 @@ class ETInstaller( ) : NativeETInstallerSpec(reactContext) { companion object { const val NAME = NativeETInstallerSpec.NAME + + @JvmStatic + @DoNotStrip + @Throws(Exception::class) + fun fetchByteDataFromUrl(source: String): ByteArray? { + try { + val url = URL(source) + val connection = url.openConnection() + connection.connect() + + val inputStream: InputStream = connection.getInputStream() + val data = inputStream.readBytes() + inputStream.close() + + return data + } catch (exception: Throwable) { + return null + } + } } private val mHybridData: HybridData @@ -32,7 +54,7 @@ class ETInstaller( val jsCallInvokerHolder = reactContext.jsCallInvokerHolder as CallInvokerHolderImpl mHybridData = initHybrid(reactContext.javaScriptContextHolder!!.get(), jsCallInvokerHolder) } catch (exception: UnsatisfiedLinkError) { - throw RuntimeException("Could not load native module Install", exception) + throw RuntimeException("Could not load native module ETInstaller", exception) } } diff --git a/android/src/main/java/com/swmansion/rnexecutorch/ImageSegmentation.kt b/android/src/main/java/com/swmansion/rnexecutorch/ImageSegmentation.kt deleted file mode 100644 index c18fa8ed32..0000000000 --- a/android/src/main/java/com/swmansion/rnexecutorch/ImageSegmentation.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.swmansion.rnexecutorch - -import android.util.Log -import com.facebook.react.bridge.Promise -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReadableArray -import com.swmansion.rnexecutorch.models.imagesegmentation.ImageSegmentationModel -import com.swmansion.rnexecutorch.utils.ETError -import com.swmansion.rnexecutorch.utils.ImageProcessor -import org.opencv.android.OpenCVLoader - -class ImageSegmentation( - reactContext: ReactApplicationContext, -) : NativeImageSegmentationSpec(reactContext) { - private lateinit var model: ImageSegmentationModel - - companion object { - const val NAME = "ImageSegmentation" - - init { - if (!OpenCVLoader.initLocal()) { - Log.d("rn_executorch", "OpenCV not loaded") - } else { - Log.d("rn_executorch", "OpenCV loaded") - } - } - } - - override fun loadModule( - modelSource: String, - promise: Promise, - ) { - try { - model = ImageSegmentationModel(reactApplicationContext) - model.loadModel(modelSource) - promise.resolve(0) - } catch (e: Exception) { - promise.reject(e.message!!, ETError.InvalidModelSource.toString()) - } - } - - override fun forward( - input: String, - classesOfInterest: ReadableArray, - resize: Boolean, - promise: Promise, - ) { - try { - val output = - model.runModel(Triple(ImageProcessor.readImage(input), classesOfInterest, resize)) - promise.resolve(output) - } catch (e: Exception) { - promise.reject(e.message!!, e.message) - } - } - - override fun getName(): String = NAME -} diff --git a/android/src/main/java/com/swmansion/rnexecutorch/RnExecutorchPackage.kt b/android/src/main/java/com/swmansion/rnexecutorch/RnExecutorchPackage.kt index 8e0092b37e..ee289e7a1d 100644 --- a/android/src/main/java/com/swmansion/rnexecutorch/RnExecutorchPackage.kt +++ b/android/src/main/java/com/swmansion/rnexecutorch/RnExecutorchPackage.kt @@ -18,8 +18,6 @@ class RnExecutorchPackage : TurboReactPackage() { LLM(reactContext) } else if (name == ETModule.NAME) { ETModule(reactContext) - } else if (name == StyleTransfer.NAME) { - StyleTransfer(reactContext) } else if (name == Classification.NAME) { Classification(reactContext) } else if (name == ObjectDetection.NAME) { @@ -30,8 +28,6 @@ class RnExecutorchPackage : TurboReactPackage() { OCR(reactContext) } else if (name == VerticalOCR.NAME) { VerticalOCR(reactContext) - } else if (name == ImageSegmentation.NAME) { - ImageSegmentation(reactContext) } else if (name == ETInstaller.NAME) { ETInstaller(reactContext) } else if (name == Tokenizer.NAME) { @@ -66,17 +62,6 @@ class RnExecutorchPackage : TurboReactPackage() { true, ) - moduleInfos[StyleTransfer.NAME] = - ReactModuleInfo( - StyleTransfer.NAME, - StyleTransfer.NAME, - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - true, - ) - moduleInfos[Classification.NAME] = ReactModuleInfo( Classification.NAME, @@ -132,17 +117,6 @@ class RnExecutorchPackage : TurboReactPackage() { true, ) - moduleInfos[ImageSegmentation.NAME] = - ReactModuleInfo( - ImageSegmentation.NAME, - ImageSegmentation.NAME, - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - true, - ) - moduleInfos[Tokenizer.NAME] = ReactModuleInfo( Tokenizer.NAME, diff --git a/android/src/main/java/com/swmansion/rnexecutorch/StyleTransfer.kt b/android/src/main/java/com/swmansion/rnexecutorch/StyleTransfer.kt deleted file mode 100644 index 224794e17f..0000000000 --- a/android/src/main/java/com/swmansion/rnexecutorch/StyleTransfer.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.swmansion.rnexecutorch - -import android.util.Log -import com.facebook.react.bridge.Promise -import com.facebook.react.bridge.ReactApplicationContext -import com.swmansion.rnexecutorch.models.styletransfer.StyleTransferModel -import com.swmansion.rnexecutorch.utils.ETError -import com.swmansion.rnexecutorch.utils.ImageProcessor -import org.opencv.android.OpenCVLoader - -class StyleTransfer( - reactContext: ReactApplicationContext, -) : NativeStyleTransferSpec(reactContext) { - private lateinit var styleTransferModel: StyleTransferModel - - companion object { - const val NAME = "StyleTransfer" - - init { - if (!OpenCVLoader.initLocal()) { - Log.d("rn_executorch", "OpenCV not loaded") - } else { - Log.d("rn_executorch", "OpenCV loaded") - } - } - } - - override fun loadModule( - modelSource: String, - promise: Promise, - ) { - try { - styleTransferModel = StyleTransferModel(reactApplicationContext) - styleTransferModel.loadModel(modelSource) - promise.resolve(0) - } catch (e: Exception) { - promise.reject(e.message!!, ETError.InvalidModelSource.toString()) - } - } - - override fun forward( - input: String, - promise: Promise, - ) { - try { - val output = styleTransferModel.runModel(ImageProcessor.readImage(input)) - promise.resolve(ImageProcessor.saveToTempFile(reactApplicationContext, output)) - } catch (e: Exception) { - promise.reject(e.message!!, e.message) - } - } - - override fun getName(): String = NAME -} diff --git a/android/src/main/java/com/swmansion/rnexecutorch/models/imageSegmentation/Constants.kt b/android/src/main/java/com/swmansion/rnexecutorch/models/imageSegmentation/Constants.kt deleted file mode 100644 index 7ba7fcb5c1..0000000000 --- a/android/src/main/java/com/swmansion/rnexecutorch/models/imageSegmentation/Constants.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.swmansion.rnexecutorch.models.imagesegmentation - -val deeplabv3_resnet50_labels: Array = - arrayOf( - "BACKGROUND", - "AEROPLANE", - "BICYCLE", - "BIRD", - "BOAT", - "BOTTLE", - "BUS", - "CAR", - "CAT", - "CHAIR", - "COW", - "DININGTABLE", - "DOG", - "HORSE", - "MOTORBIKE", - "PERSON", - "POTTEDPLANT", - "SHEEP", - "SOFA", - "TRAIN", - "TVMONITOR", - ) diff --git a/android/src/main/java/com/swmansion/rnexecutorch/models/imageSegmentation/ImageSegmentationModel.kt b/android/src/main/java/com/swmansion/rnexecutorch/models/imageSegmentation/ImageSegmentationModel.kt deleted file mode 100644 index 36c1594b49..0000000000 --- a/android/src/main/java/com/swmansion/rnexecutorch/models/imageSegmentation/ImageSegmentationModel.kt +++ /dev/null @@ -1,139 +0,0 @@ -package com.swmansion.rnexecutorch.models.imagesegmentation - -import com.facebook.react.bridge.Arguments -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReadableArray -import com.facebook.react.bridge.WritableMap -import com.swmansion.rnexecutorch.models.BaseModel -import com.swmansion.rnexecutorch.utils.ArrayUtils -import com.swmansion.rnexecutorch.utils.ImageProcessor -import com.swmansion.rnexecutorch.utils.softmax -import org.opencv.core.CvType -import org.opencv.core.Mat -import org.opencv.core.Size -import org.opencv.imgproc.Imgproc -import org.pytorch.executorch.EValue - -class ImageSegmentationModel( - reactApplicationContext: ReactApplicationContext, -) : BaseModel, WritableMap>(reactApplicationContext) { - private lateinit var originalSize: Size - - private fun getModelImageSize(): Size { - val inputShape = module.getInputShape(0) - val width = inputShape[inputShape.lastIndex] - val height = inputShape[inputShape.lastIndex - 1] - - return Size(height.toDouble(), width.toDouble()) - } - - fun preprocess(input: Mat): EValue { - originalSize = input.size() - Imgproc.resize(input, input, getModelImageSize()) - return ImageProcessor.matToEValue(input, module.getInputShape(0)) - } - - private fun extractResults( - result: FloatArray, - numLabels: Int, - resize: Boolean, - ): List { - val modelSize = getModelImageSize() - val numModelPixels = (modelSize.height * modelSize.width).toInt() - - val extractedLabelScores = mutableListOf() - - for (label in 0.., - numLabels: Int, - outputSize: Size, - ): IntArray { - val numPixels = (outputSize.height * outputSize.width).toInt() - val argMax = IntArray(numPixels) - for (pixel in 0..() - for (buffer in labelScores) { - scores.add(buffer[pixel]) - } - val adjustedScores = softmax(scores.toTypedArray()) - for (label in 0.., - classesOfInterest: ReadableArray, - resize: Boolean, - ): WritableMap { - val outputData = output[0].toTensor().dataAsFloatArray - val modelSize = getModelImageSize() - val numLabels = deeplabv3_resnet50_labels.size - - require(outputData.count() == (numLabels * modelSize.height * modelSize.width).toInt()) { "Model generated unexpected output size." } - - val outputSize = if (resize) originalSize else modelSize - - val extractedResults = extractResults(outputData, numLabels, resize) - - val argMax = adjustScoresPerPixel(extractedResults, numLabels, outputSize) - - val labelSet = mutableSetOf() - // Filter by the label set when base class changed - for (i in 0..): WritableMap { - val modelInput = preprocess(input.first) - val modelOutput = forward(modelInput) - return postprocess(modelOutput, input.second, input.third) - } -} diff --git a/android/src/main/java/com/swmansion/rnexecutorch/models/styleTransfer/StyleTransferModel.kt b/android/src/main/java/com/swmansion/rnexecutorch/models/styleTransfer/StyleTransferModel.kt deleted file mode 100644 index 4019015dd8..0000000000 --- a/android/src/main/java/com/swmansion/rnexecutorch/models/styleTransfer/StyleTransferModel.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.swmansion.rnexecutorch.models.styletransfer - -import com.facebook.react.bridge.ReactApplicationContext -import com.swmansion.rnexecutorch.utils.ImageProcessor -import org.opencv.core.Mat -import org.opencv.core.Size -import org.opencv.imgproc.Imgproc -import org.pytorch.executorch.EValue -import com.swmansion.rnexecutorch.models.BaseModel - -class StyleTransferModel( - reactApplicationContext: ReactApplicationContext, -) : BaseModel(reactApplicationContext) { - private lateinit var originalSize: Size - - private fun getModelImageSize(): Size { - val inputShape = module.getInputShape(0) - val width = inputShape[inputShape.lastIndex] - val height = inputShape[inputShape.lastIndex - 1] - - return Size(height.toDouble(), width.toDouble()) - } - - fun preprocess(input: Mat): EValue { - originalSize = input.size() - Imgproc.resize(input, input, getModelImageSize()) - return ImageProcessor.matToEValue(input, module.getInputShape(0)) - } - - fun postprocess(output: Array): Mat { - val tensor = output[0].toTensor() - val modelShape = getModelImageSize() - val result = ImageProcessor.eValueToMat(tensor.dataAsFloatArray, modelShape.width.toInt(), modelShape.height.toInt()) - Imgproc.resize(result, result, originalSize) - return result - } - - override fun runModel(input: Mat): Mat { - val modelInput = preprocess(input) - val modelOutput = forward(modelInput) - return postprocess(modelOutput) - } -} diff --git a/common/RnExecutorchInstaller.h b/common/RnExecutorchInstaller.h deleted file mode 100644 index f2118fd1e8..0000000000 --- a/common/RnExecutorchInstaller.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include "jsi/JsiPromise.h" - -namespace rnexecutorch { - -using namespace facebook; - -class RnExecutorchInstaller { -public: - static void - injectJSIBindings(jsi::Runtime *jsiRuntime, - const std::shared_ptr &jsCallInvoker) { - // Install JSI methods here - } - -private: -}; - -} // namespace rnexecutorch \ No newline at end of file diff --git a/common/ada/ada.cpp b/common/ada/ada.cpp new file mode 100644 index 0000000000..2f9263a1fd --- /dev/null +++ b/common/ada/ada.cpp @@ -0,0 +1,17406 @@ +/* auto-generated on 2025-01-30 14:25:38 -0500. Do not edit! */ +/* begin file src/ada.cpp */ +#include "ada.h" +/* begin file src/checkers.cpp */ + +#include +#include +#include + +namespace ada::checkers { + +ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept { + // The string is not empty and does not contain upper case ASCII characters. + // + // Optimization. To be considered as a possible ipv4, the string must end + // with 'x' or a lowercase hex character. + // Most of the time, this will be false so this simple check will save a lot + // of effort. + // If the address ends with a dot, we need to prune it (special case). + if (view.ends_with('.')) { + view.remove_suffix(1); + if (view.empty()) { + return false; + } + } + char last_char = view.back(); + bool possible_ipv4 = (last_char >= '0' && last_char <= '9') || + (last_char >= 'a' && last_char <= 'f') || + last_char == 'x'; + if (!possible_ipv4) { + return false; + } + // From the last character, find the last dot. + size_t last_dot = view.rfind('.'); + if (last_dot != std::string_view::npos) { + // We have at least one dot. + view = view.substr(last_dot + 1); + } + /** Optimization opportunity: we have basically identified the last number of + the ipv4 if we return true here. We might as well parse it and have at + least one number parsed when we get to parse_ipv4. */ + if (std::ranges::all_of(view, ada::checkers::is_digit)) { + return true; + } + // It could be hex (0x), but not if there is a single character. + if (view.size() == 1) { + return false; + } + // It must start with 0x. + if (!view.starts_with("0x")) { + return false; + } + // We must allow "0x". + if (view.size() == 2) { + return true; + } + // We have 0x followed by some characters, we need to check that they are + // hexadecimals. + return std::all_of(view.begin() + 2, view.end(), + ada::unicode::is_lowercase_hex); +} + +// for use with path_signature, we include all characters that need percent +// encoding. +static constexpr std::array path_signature_table = + []() consteval { + std::array result{}; + for (size_t i = 0; i < 256; i++) { + if (i <= 0x20 || i == 0x22 || i == 0x23 || i == 0x3c || i == 0x3e || + i == 0x3f || i == 0x60 || i == 0x7b || i == 0x7d || i > 0x7e) { + result[i] = 1; + } else if (i == 0x25) { + result[i] = 8; + } else if (i == 0x2e) { + result[i] = 4; + } else if (i == 0x5c) { + result[i] = 2; + } else { + result[i] = 0; + } + } + return result; + }(); + +ada_really_inline constexpr uint8_t +path_signature(std::string_view input) noexcept { + // The path percent-encode set is the query percent-encode set and U+003F (?), + // U+0060 (`), U+007B ({), and U+007D (}). The query percent-encode set is the + // C0 control percent-encode set and U+0020 SPACE, U+0022 ("), U+0023 (#), + // U+003C (<), and U+003E (>). The C0 control percent-encode set are the C0 + // controls and all code points greater than U+007E (~). + size_t i = 0; + uint8_t accumulator{}; + for (; i + 7 < input.size(); i += 8) { + accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] | + path_signature_table[uint8_t(input[i + 1])] | + path_signature_table[uint8_t(input[i + 2])] | + path_signature_table[uint8_t(input[i + 3])] | + path_signature_table[uint8_t(input[i + 4])] | + path_signature_table[uint8_t(input[i + 5])] | + path_signature_table[uint8_t(input[i + 6])] | + path_signature_table[uint8_t(input[i + 7])]); + } + for (; i < input.size(); i++) { + accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]); + } + return accumulator; +} + +ada_really_inline constexpr bool +verify_dns_length(std::string_view input) noexcept { + if (input.back() == '.') { + if (input.size() > 254) + return false; + } else if (input.size() > 253) + return false; + + size_t start = 0; + while (start < input.size()) { + auto dot_location = input.find('.', start); + // If not found, it's likely the end of the domain + if (dot_location == std::string_view::npos) + dot_location = input.size(); + + auto label_size = dot_location - start; + if (label_size > 63 || label_size == 0) + return false; + + start = dot_location + 1; + } + + return true; +} +} // namespace ada::checkers +/* end file src/checkers.cpp */ +/* begin file src/unicode.cpp */ + +ADA_PUSH_DISABLE_ALL_WARNINGS +/* begin file src/ada_idna.cpp */ +/* auto-generated on 2024-12-18 09:44:34 -0500. Do not edit! */ +/* begin file src/idna.cpp */ +/* begin file src/unicode_transcoding.cpp */ + +#include +#include +#include + +namespace ada::idna { + +size_t utf8_to_utf32(const char *buf, size_t len, char32_t *utf32_output) { + const uint8_t *data = reinterpret_cast(buf); + size_t pos = 0; + char32_t *start{utf32_output}; + while (pos < len) { + // try to convert the next block of 16 ASCII bytes + if (pos + 16 <= len) { // if it is safe to read 16 more + // bytes, check that they are ascii + uint64_t v1; + std::memcpy(&v1, data + pos, sizeof(uint64_t)); + uint64_t v2; + std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); + uint64_t v{v1 | v2}; + if ((v & 0x8080808080808080) == 0) { + size_t final_pos = pos + 16; + while (pos < final_pos) { + *utf32_output++ = char32_t(buf[pos]); + pos++; + } + continue; + } + } + uint8_t leading_byte = data[pos]; // leading byte + if (leading_byte < 0b10000000) { + // converting one ASCII byte !!! + *utf32_output++ = char32_t(leading_byte); + pos++; + } else if ((leading_byte & 0b11100000) == 0b11000000) { + // We have a two-byte UTF-8 + if (pos + 1 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t code_point = + (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); + if (code_point < 0x80 || 0x7ff < code_point) { + return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 2; + } else if ((leading_byte & 0b11110000) == 0b11100000) { + // We have a three-byte UTF-8 + if (pos + 2 >= len) { + return 0; + } // minimal bound checking + + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return 0; + } + // range check + uint32_t code_point = (leading_byte & 0b00001111) << 12 | + (data[pos + 1] & 0b00111111) << 6 | + (data[pos + 2] & 0b00111111); + if (code_point < 0x800 || 0xffff < code_point || + (0xd7ff < code_point && code_point < 0xe000)) { + return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 3; + } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 + // we have a 4-byte UTF-8 word. + if (pos + 3 >= len) { + return 0; + } // minimal bound checking + if ((data[pos + 1] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 2] & 0b11000000) != 0b10000000) { + return 0; + } + if ((data[pos + 3] & 0b11000000) != 0b10000000) { + return 0; + } + + // range check + uint32_t code_point = (leading_byte & 0b00000111) << 18 | + (data[pos + 1] & 0b00111111) << 12 | + (data[pos + 2] & 0b00111111) << 6 | + (data[pos + 3] & 0b00111111); + if (code_point <= 0xffff || 0x10ffff < code_point) { + return 0; + } + *utf32_output++ = char32_t(code_point); + pos += 4; + } else { + return 0; + } + } + return utf32_output - start; +} + +size_t utf8_length_from_utf32(const char32_t *buf, size_t len) { + // We are not BOM aware. + const uint32_t *p = reinterpret_cast(buf); + size_t counter{0}; + for (size_t i = 0; i != len; ++i) { + ++counter; // ASCII + counter += static_cast(p[i] > 0x7F); // two-byte + counter += static_cast(p[i] > 0x7FF); // three-byte + counter += static_cast(p[i] > 0xFFFF); // four-bytes + } + return counter; +} + +size_t utf32_length_from_utf8(const char *buf, size_t len) { + const int8_t *p = reinterpret_cast(buf); + return std::count_if(p, std::next(p, len), [](int8_t c) { + // -65 is 0b10111111, anything larger in two-complement's + // should start a new code point. + return c > -65; + }); +} + +size_t utf32_to_utf8(const char32_t *buf, size_t len, char *utf8_output) { + const uint32_t *data = reinterpret_cast(buf); + size_t pos = 0; + char *start{utf8_output}; + while (pos < len) { + // try to convert the next block of 2 ASCII characters + if (pos + 2 <= len) { // if it is safe to read 8 more + // bytes, check that they are ascii + uint64_t v; + std::memcpy(&v, data + pos, sizeof(uint64_t)); + if ((v & 0xFFFFFF80FFFFFF80) == 0) { + *utf8_output++ = char(buf[pos]); + *utf8_output++ = char(buf[pos + 1]); + pos += 2; + continue; + } + } + uint32_t word = data[pos]; + if ((word & 0xFFFFFF80) == 0) { + // will generate one UTF-8 bytes + *utf8_output++ = char(word); + pos++; + } else if ((word & 0xFFFFF800) == 0) { + // will generate two UTF-8 bytes + // we have 0b110XXXXX 0b10XXXXXX + *utf8_output++ = char((word >> 6) | 0b11000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); + pos++; + } else if ((word & 0xFFFF0000) == 0) { + // will generate three UTF-8 bytes + // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX + if (word >= 0xD800 && word <= 0xDFFF) { + return 0; + } + *utf8_output++ = char((word >> 12) | 0b11100000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); + pos++; + } else { + // will generate four UTF-8 bytes + // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX + // 0b10XXXXXX + if (word > 0x10FFFF) { + return 0; + } + *utf8_output++ = char((word >> 18) | 0b11110000); + *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); + *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); + *utf8_output++ = char((word & 0b111111) | 0b10000000); + pos++; + } + } + return utf8_output - start; +} +} // namespace ada::idna +/* end file src/unicode_transcoding.cpp */ +/* begin file src/mapping.cpp */ + +#include +#include +#include + +/* begin file src/mapping_tables.cpp */ +// IDNA 15.1.0 + +// clang-format off +#ifndef ADA_IDNA_TABLES_H +#define ADA_IDNA_TABLES_H +#include + +namespace ada::idna { + +const uint32_t mappings[5165] = +{ + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 32, 32, 776, 32, 772, 50, 51, 32, 769, + 956, 32, 807, 49, 49, 8260, 52, 49, 8260, 50, 51, 8260, 52, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 257, 259, 261, 263, 265, 267, + 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, + 301, 303, 105, 775, 309, 311, 314, 316, 318, 108, 183, 322, 324, 326, 328, 700, + 110, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, + 361, 363, 365, 367, 369, 371, 373, 375, 255, 378, 380, 382, 595, 387, 389, 596, + 392, 598, 599, 396, 477, 601, 603, 402, 608, 611, 617, 616, 409, 623, 626, 629, + 417, 419, 421, 640, 424, 643, 429, 648, 432, 650, 651, 436, 438, 658, 441, 445, + 100, 382, 108, 106, 110, 106, 462, 464, 466, 468, 470, 472, 474, 476, 479, 481, + 483, 485, 487, 489, 491, 493, 495, 100, 122, 501, 405, 447, 505, 507, 509, 511, + 513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537, 539, 541, 543, + 414, 547, 549, 551, 553, 555, 557, 559, 561, 563, 11365, 572, 410, 11366, 578, 384, + 649, 652, 583, 585, 587, 589, 591, 614, 633, 635, 641, 32, 774, 32, 775, 32, 778, + 32, 808, 32, 771, 32, 779, 661, 768, 787, 776, 769, 953, 881, 883, 697, 887, 32, + 953, 59, 1011, 32, 776, 769, 940, 941, 942, 943, 972, 973, 974, 945, 946, 947, 948, + 949, 950, 951, 952, 954, 955, 957, 958, 959, 960, 961, 963, 964, 965, 966, 967, + 968, 969, 970, 971, 983, 985, 987, 989, 991, 993, 995, 997, 999, 1001, 1003, 1005, + 1007, 1016, 1019, 891, 892, 893, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, + 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1072, 1073, 1074, 1075, 1076, 1077, + 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, + 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1121, 1123, + 1125, 1127, 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151, + 1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187, + 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215, + 1218, 1220, 1222, 1224, 1226, 1228, 1230, 1233, 1235, 1237, 1239, 1241, 1243, 1245, + 1247, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1271, 1273, + 1275, 1277, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299, 1301, + 1303, 1305, 1307, 1309, 1311, 1313, 1315, 1317, 1319, 1321, 1323, 1325, 1327, 1377, + 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, + 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, + 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1381, 1410, 1575, 1652, 1608, + 1652, 1735, 1652, 1610, 1652, 2325, 2364, 2326, 2364, 2327, 2364, 2332, 2364, 2337, + 2364, 2338, 2364, 2347, 2364, 2351, 2364, 2465, 2492, 2466, 2492, 2479, 2492, 2610, + 2620, 2616, 2620, 2582, 2620, 2583, 2620, 2588, 2620, 2603, 2620, 2849, 2876, 2850, + 2876, 3661, 3634, 3789, 3762, 3755, 3737, 3755, 3745, 3851, 3906, 4023, 3916, 4023, + 3921, 4023, 3926, 4023, 3931, 4023, 3904, 4021, 3953, 3954, 3953, 3956, 4018, 3968, + 4018, 3953, 3968, 4019, 3968, 4019, 3953, 3968, 3986, 4023, 3996, 4023, 4001, 4023, + 4006, 4023, 4011, 4023, 3984, 4021, 11559, 11565, 4316, 5104, 5105, 5106, 5107, + 5108, 5109, 42571, 4304, 4305, 4306, 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314, + 4315, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, + 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343, + 4344, 4345, 4346, 4349, 4350, 4351, 592, 593, 7426, 604, 7446, 7447, 7453, 7461, + 594, 597, 607, 609, 613, 618, 7547, 669, 621, 7557, 671, 625, 624, 627, 628, 632, + 642, 427, 7452, 656, 657, 7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, + 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, + 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, + 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, + 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, + 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 7829, 97, 702, 223, 7841, + 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, 7867, 7869, + 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895, 7897, + 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, + 7927, 7929, 7931, 7933, 7935, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 7952, + 7953, 7954, 7955, 7956, 7957, 7968, 7969, 7970, 7971, 7972, 7973, 7974, 7975, 7984, + 7985, 7986, 7987, 7988, 7989, 7990, 7991, 8000, 8001, 8002, 8003, 8004, 8005, 8017, + 8019, 8021, 8023, 8032, 8033, 8034, 8035, 8036, 8037, 8038, 8039, 7936, 953, 7937, + 953, 7938, 953, 7939, 953, 7940, 953, 7941, 953, 7942, 953, 7943, 953, 7968, 953, + 7969, 953, 7970, 953, 7971, 953, 7972, 953, 7973, 953, 7974, 953, 7975, 953, 8032, + 953, 8033, 953, 8034, 953, 8035, 953, 8036, 953, 8037, 953, 8038, 953, 8039, 953, + 8048, 953, 945, 953, 940, 953, 8118, 953, 8112, 8113, 32, 787, 32, 834, 32, 776, + 834, 8052, 953, 951, 953, 942, 953, 8134, 953, 8050, 32, 787, 768, 32, 787, 769, + 32, 787, 834, 912, 8144, 8145, 8054, 32, 788, 768, 32, 788, 769, 32, 788, 834, 944, + 8160, 8161, 8058, 8165, 32, 776, 768, 96, 8060, 953, 969, 953, 974, 953, 8182, 953, + 8056, 8208, 32, 819, 8242, 8242, 8242, 8242, 8242, 8245, 8245, 8245, 8245, 8245, + 33, 33, 32, 773, 63, 63, 63, 33, 33, 63, 48, 53, 54, 55, 56, 57, 43, 8722, 61, 40, + 41, 97, 47, 99, 97, 47, 115, 176, 99, 99, 47, 111, 99, 47, 117, 176, 102, 115, 109, + 116, 101, 108, 116, 109, 1488, 1489, 1490, 1491, 102, 97, 120, 8721, 49, 8260, 55, + 49, 8260, 57, 49, 8260, 49, 48, 49, 8260, 51, 50, 8260, 51, 49, 8260, 53, 50, 8260, + 53, 51, 8260, 53, 52, 8260, 53, 49, 8260, 54, 53, 8260, 54, 49, 8260, 56, 51, 8260, + 56, 53, 8260, 56, 55, 8260, 56, 105, 105, 105, 105, 105, 105, 118, 118, 105, 118, + 105, 105, 118, 105, 105, 105, 105, 120, 120, 105, 120, 105, 105, 48, 8260, 51, 8747, + 8747, 8747, 8747, 8747, 8750, 8750, 8750, 8750, 8750, 12296, 12297, 49, 50, 49, + 51, 49, 52, 49, 53, 49, 54, 49, 55, 49, 56, 49, 57, 50, 48, 40, 49, 41, 40, 50, + 41, 40, 51, 41, 40, 52, 41, 40, 53, 41, 40, 54, 41, 40, 55, 41, 40, 56, 41, 40, + 57, 41, 40, 49, 48, 41, 40, 49, 49, 41, 40, 49, 50, 41, 40, 49, 51, 41, 40, 49, + 52, 41, 40, 49, 53, 41, 40, 49, 54, 41, 40, 49, 55, 41, 40, 49, 56, 41, 40, 49, + 57, 41, 40, 50, 48, 41, 40, 97, 41, 40, 98, 41, 40, 99, 41, 40, 100, 41, 40, 101, + 41, 40, 102, 41, 40, 103, 41, 40, 104, 41, 40, 105, 41, 40, 106, 41, 40, 107, 41, + 40, 108, 41, 40, 109, 41, 40, 110, 41, 40, 111, 41, 40, 112, 41, 40, 113, 41, 40, + 114, 41, 40, 115, 41, 40, 116, 41, 40, 117, 41, 40, 118, 41, 40, 119, 41, 40, 120, + 41, 40, 121, 41, 40, 122, 41, 58, 58, 61, 61, 61, 10973, 824, 11312, 11313, 11314, + 11315, 11316, 11317, 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325, 11326, + 11327, 11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, + 11339, 11340, 11341, 11342, 11343, 11344, 11345, 11346, 11347, 11348, 11349, 11350, + 11351, 11352, 11353, 11354, 11355, 11356, 11357, 11358, 11359, 11361, 619, 7549, + 637, 11368, 11370, 11372, 11379, 11382, 575, 576, 11393, 11395, 11397, 11399, 11401, + 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423, 11425, + 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, + 11451, 11453, 11455, 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, + 11475, 11477, 11479, 11481, 11483, 11485, 11487, 11489, 11491, 11500, 11502, 11507, + 11617, 27597, 40863, 19968, 20008, 20022, 20031, 20057, 20101, 20108, 20128, 20154, + 20799, 20837, 20843, 20866, 20886, 20907, 20960, 20981, 20992, 21147, 21241, 21269, + 21274, 21304, 21313, 21340, 21353, 21378, 21430, 21448, 21475, 22231, 22303, 22763, + 22786, 22794, 22805, 22823, 22899, 23376, 23424, 23544, 23567, 23586, 23608, 23662, + 23665, 24027, 24037, 24049, 24062, 24178, 24186, 24191, 24308, 24318, 24331, 24339, + 24400, 24417, 24435, 24515, 25096, 25142, 25163, 25903, 25908, 25991, 26007, 26020, + 26041, 26080, 26085, 26352, 26376, 26408, 27424, 27490, 27513, 27571, 27595, 27604, + 27611, 27663, 27668, 27700, 28779, 29226, 29238, 29243, 29247, 29255, 29273, 29275, + 29356, 29572, 29577, 29916, 29926, 29976, 29983, 29992, 30000, 30091, 30098, 30326, + 30333, 30382, 30399, 30446, 30683, 30690, 30707, 31034, 31160, 31166, 31348, 31435, + 31481, 31859, 31992, 32566, 32593, 32650, 32701, 32769, 32780, 32786, 32819, 32895, + 32905, 33251, 33258, 33267, 33276, 33292, 33307, 33311, 33390, 33394, 33400, 34381, + 34411, 34880, 34892, 34915, 35198, 35211, 35282, 35328, 35895, 35910, 35925, 35960, + 35997, 36196, 36208, 36275, 36523, 36554, 36763, 36784, 36789, 37009, 37193, 37318, + 37324, 37329, 38263, 38272, 38428, 38582, 38585, 38632, 38737, 38750, 38754, 38761, + 38859, 38893, 38899, 38913, 39080, 39131, 39135, 39318, 39321, 39340, 39592, 39640, + 39647, 39717, 39727, 39730, 39740, 39770, 40165, 40565, 40575, 40613, 40635, 40643, + 40653, 40657, 40697, 40701, 40718, 40723, 40736, 40763, 40778, 40786, 40845, 40860, + 40864, 46, 12306, 21316, 21317, 32, 12441, 32, 12442, 12424, 12426, 12467, 12488, + 4352, 4353, 4522, 4354, 4524, 4525, 4355, 4356, 4357, 4528, 4529, 4530, 4531, 4532, + 4533, 4378, 4358, 4359, 4360, 4385, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, + 4369, 4370, 4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, + 4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469, 4372, 4373, 4551, 4552, 4556, + 4558, 4563, 4567, 4569, 4380, 4573, 4575, 4381, 4382, 4384, 4386, 4387, 4391, 4393, + 4395, 4396, 4397, 4398, 4399, 4402, 4406, 4416, 4423, 4428, 4593, 4594, 4439, 4440, + 4441, 4484, 4485, 4488, 4497, 4498, 4500, 4510, 4513, 19977, 22235, 19978, 20013, + 19979, 30002, 19993, 19969, 22825, 22320, 40, 4352, 41, 40, 4354, 41, 40, 4355, + 41, 40, 4357, 41, 40, 4358, 41, 40, 4359, 41, 40, 4361, 41, 40, 4363, 41, 40, 4364, + 41, 40, 4366, 41, 40, 4367, 41, 40, 4368, 41, 40, 4369, 41, 40, 4370, 41, 40, 44032, + 41, 40, 45208, 41, 40, 45796, 41, 40, 46972, 41, 40, 47560, 41, 40, 48148, 41, 40, + 49324, 41, 40, 50500, 41, 40, 51088, 41, 40, 52264, 41, 40, 52852, 41, 40, 53440, + 41, 40, 54028, 41, 40, 54616, 41, 40, 51452, 41, 40, 50724, 51204, 41, 40, 50724, + 54980, 41, 40, 19968, 41, 40, 20108, 41, 40, 19977, 41, 40, 22235, 41, 40, 20116, + 41, 40, 20845, 41, 40, 19971, 41, 40, 20843, 41, 40, 20061, 41, 40, 21313, 41, 40, + 26376, 41, 40, 28779, 41, 40, 27700, 41, 40, 26408, 41, 40, 37329, 41, 40, 22303, + 41, 40, 26085, 41, 40, 26666, 41, 40, 26377, 41, 40, 31038, 41, 40, 21517, 41, 40, + 29305, 41, 40, 36001, 41, 40, 31069, 41, 40, 21172, 41, 40, 20195, 41, 40, 21628, + 41, 40, 23398, 41, 40, 30435, 41, 40, 20225, 41, 40, 36039, 41, 40, 21332, 41, 40, + 31085, 41, 40, 20241, 41, 40, 33258, 41, 40, 33267, 41, 21839, 24188, 31631, 112, + 116, 101, 50, 50, 50, 52, 50, 53, 50, 54, 50, 55, 50, 56, 50, 57, 51, 48, 51, 51, + 51, 52, 51, 53, 52280, 44256, 51452, 51032, 50864, 31192, 30007, 36969, 20778, 21360, + 27880, 38917, 20889, 27491, 24038, 21491, 21307, 23447, 22812, 51, 54, 51, 55, 51, + 56, 51, 57, 52, 48, 52, 52, 52, 53, 52, 54, 52, 55, 52, 56, 52, 57, 53, 48, 49, + 26376, 50, 26376, 51, 26376, 52, 26376, 53, 26376, 54, 26376, 55, 26376, 56, 26376, + 57, 26376, 49, 48, 26376, 49, 49, 26376, 49, 50, 26376, 104, 103, 101, 114, 103, + 101, 118, 108, 116, 100, 12450, 12452, 12454, 12456, 12458, 12459, 12461, 12463, + 12465, 12469, 12471, 12473, 12475, 12477, 12479, 12481, 12484, 12486, 12490, 12491, + 12492, 12493, 12494, 12495, 12498, 12501, 12504, 12507, 12510, 12511, 12512, 12513, + 12514, 12516, 12518, 12520, 12521, 12522, 12523, 12524, 12525, 12527, 12528, 12529, + 12530, 20196, 21644, 12450, 12497, 12540, 12488, 12450, 12523, 12501, 12449, 12450, + 12531, 12506, 12450, 12450, 12540, 12523, 12452, 12491, 12531, 12464, 12452, 12531, + 12481, 12454, 12457, 12531, 12456, 12473, 12463, 12540, 12489, 12456, 12540, 12459, + 12540, 12458, 12531, 12473, 12458, 12540, 12512, 12459, 12452, 12522, 12459, 12521, + 12483, 12488, 12459, 12525, 12522, 12540, 12460, 12525, 12531, 12460, 12531, 12510, + 12462, 12460, 12462, 12491, 12540, 12461, 12517, 12522, 12540, 12462, 12523, 12480, + 12540, 12461, 12525, 12461, 12525, 12464, 12521, 12512, 12461, 12525, 12513, 12540, + 12488, 12523, 12461, 12525, 12527, 12483, 12488, 12464, 12521, 12512, 12488, 12531, + 12463, 12523, 12476, 12452, 12525, 12463, 12525, 12540, 12493, 12465, 12540, 12473, + 12467, 12523, 12490, 12467, 12540, 12509, 12469, 12452, 12463, 12523, 12469, 12531, + 12481, 12540, 12512, 12471, 12522, 12531, 12464, 12475, 12531, 12481, 12475, 12531, + 12488, 12480, 12540, 12473, 12487, 12471, 12489, 12523, 12490, 12494, 12494, 12483, + 12488, 12495, 12452, 12484, 12497, 12540, 12475, 12531, 12488, 12497, 12540, 12484, + 12496, 12540, 12524, 12523, 12500, 12450, 12473, 12488, 12523, 12500, 12463, 12523, + 12500, 12467, 12499, 12523, 12501, 12449, 12521, 12483, 12489, 12501, 12451, 12540, + 12488, 12502, 12483, 12471, 12455, 12523, 12501, 12521, 12531, 12504, 12463, 12479, + 12540, 12523, 12506, 12477, 12506, 12491, 12498, 12504, 12523, 12484, 12506, 12531, + 12473, 12506, 12540, 12472, 12505, 12540, 12479, 12509, 12452, 12531, 12488, 12508, + 12523, 12488, 12507, 12531, 12509, 12531, 12489, 12507, 12540, 12523, 12507, 12540, + 12531, 12510, 12452, 12463, 12525, 12510, 12452, 12523, 12510, 12483, 12495, 12510, + 12523, 12463, 12510, 12531, 12471, 12519, 12531, 12511, 12463, 12525, 12531, 12511, + 12522, 12511, 12522, 12496, 12540, 12523, 12513, 12460, 12513, 12460, 12488, 12531, + 12516, 12540, 12489, 12516, 12540, 12523, 12518, 12450, 12531, 12522, 12483, 12488, + 12523, 12522, 12521, 12523, 12500, 12540, 12523, 12540, 12502, 12523, 12524, 12512, + 12524, 12531, 12488, 12466, 12531, 48, 28857, 49, 28857, 50, 28857, 51, 28857, 52, + 28857, 53, 28857, 54, 28857, 55, 28857, 56, 28857, 57, 28857, 49, 48, 28857, 49, + 49, 28857, 49, 50, 28857, 49, 51, 28857, 49, 52, 28857, 49, 53, 28857, 49, 54, 28857, + 49, 55, 28857, 49, 56, 28857, 49, 57, 28857, 50, 48, 28857, 50, 49, 28857, 50, 50, + 28857, 50, 51, 28857, 50, 52, 28857, 104, 112, 97, 100, 97, 97, 117, 98, 97, 114, + 111, 118, 112, 99, 100, 109, 100, 109, 50, 100, 109, 51, 105, 117, 24179, 25104, + 26157, 21644, 22823, 27491, 26126, 27835, 26666, 24335, 20250, 31038, 110, 97, 956, + 97, 109, 97, 107, 97, 107, 98, 109, 98, 103, 98, 99, 97, 108, 107, 99, 97, 108, + 112, 102, 110, 102, 956, 102, 956, 103, 109, 103, 107, 103, 104, 122, 107, 104, + 122, 109, 104, 122, 116, 104, 122, 956, 108, 109, 108, 100, 108, 102, 109, 110, + 109, 956, 109, 109, 109, 99, 109, 107, 109, 109, 109, 50, 99, 109, 50, 107, 109, + 50, 109, 109, 51, 99, 109, 51, 107, 109, 51, 109, 8725, 115, 109, 8725, 115, 50, + 107, 112, 97, 109, 112, 97, 103, 112, 97, 114, 97, 100, 114, 97, 100, 8725, 115, + 114, 97, 100, 8725, 115, 50, 112, 115, 110, 115, 956, 115, 109, 115, 112, 118, 110, + 118, 956, 118, 109, 118, 107, 118, 112, 119, 110, 119, 956, 119, 109, 119, 107, + 119, 107, 969, 109, 969, 98, 113, 99, 8725, 107, 103, 100, 98, 103, 121, 104, 97, + 105, 110, 107, 107, 107, 116, 108, 110, 108, 111, 103, 108, 120, 109, 105, 108, + 109, 111, 108, 112, 104, 112, 112, 109, 112, 114, 115, 118, 119, 98, 118, 8725, + 109, 97, 8725, 109, 49, 26085, 50, 26085, 51, 26085, 52, 26085, 53, 26085, 54, 26085, + 55, 26085, 56, 26085, 57, 26085, 49, 48, 26085, 49, 49, 26085, 49, 50, 26085, 49, + 51, 26085, 49, 52, 26085, 49, 53, 26085, 49, 54, 26085, 49, 55, 26085, 49, 56, 26085, + 49, 57, 26085, 50, 48, 26085, 50, 49, 26085, 50, 50, 26085, 50, 51, 26085, 50, 52, + 26085, 50, 53, 26085, 50, 54, 26085, 50, 55, 26085, 50, 56, 26085, 50, 57, 26085, + 51, 48, 26085, 51, 49, 26085, 103, 97, 108, 42561, 42563, 42565, 42567, 42569, 42573, + 42575, 42577, 42579, 42581, 42583, 42585, 42587, 42589, 42591, 42593, 42595, 42597, + 42599, 42601, 42603, 42605, 42625, 42627, 42629, 42631, 42633, 42635, 42637, 42639, + 42641, 42643, 42645, 42647, 42649, 42651, 42787, 42789, 42791, 42793, 42795, 42797, + 42799, 42803, 42805, 42807, 42809, 42811, 42813, 42815, 42817, 42819, 42821, 42823, + 42825, 42827, 42829, 42831, 42833, 42835, 42837, 42839, 42841, 42843, 42845, 42847, + 42849, 42851, 42853, 42855, 42857, 42859, 42861, 42863, 42874, 42876, 7545, 42879, + 42881, 42883, 42885, 42887, 42892, 42897, 42899, 42903, 42905, 42907, 42909, 42911, + 42913, 42915, 42917, 42919, 42921, 620, 670, 647, 43859, 42933, 42935, 42937, 42939, + 42941, 42943, 42945, 42947, 42900, 7566, 42952, 42954, 42961, 42967, 42969, 42998, + 43831, 43858, 653, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, + 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, + 5049, 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, 5061, 5062, + 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072, 5073, 5074, 5075, 5076, + 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, 5090, + 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 35912, + 26356, 36040, 28369, 20018, 21477, 22865, 21895, 22856, 25078, 30313, 32645, 34367, + 34746, 35064, 37007, 27138, 27931, 28889, 29662, 33853, 37226, 39409, 20098, 21365, + 27396, 29211, 34349, 40478, 23888, 28651, 34253, 35172, 25289, 33240, 34847, 24266, + 26391, 28010, 29436, 37070, 20358, 20919, 21214, 25796, 27347, 29200, 30439, 34310, + 34396, 36335, 38706, 39791, 40442, 30860, 31103, 32160, 33737, 37636, 35542, 22751, + 24324, 31840, 32894, 29282, 30922, 36034, 38647, 22744, 23650, 27155, 28122, 28431, + 32047, 32311, 38475, 21202, 32907, 20956, 20940, 31260, 32190, 33777, 38517, 35712, + 25295, 35582, 20025, 23527, 24594, 29575, 30064, 21271, 30971, 20415, 24489, 19981, + 27852, 25976, 32034, 21443, 22622, 30465, 33865, 35498, 27578, 27784, 25342, 33509, + 25504, 30053, 20142, 20841, 20937, 26753, 31975, 33391, 35538, 37327, 21237, 21570, + 24300, 26053, 28670, 31018, 38317, 39530, 40599, 40654, 26310, 27511, 36706, 24180, + 24976, 25088, 25754, 28451, 29001, 29833, 31178, 32244, 32879, 36646, 34030, 36899, + 37706, 21015, 21155, 21693, 28872, 35010, 24265, 24565, 25467, 27566, 31806, 29557, + 22265, 23994, 24604, 29618, 29801, 32666, 32838, 37428, 38646, 38728, 38936, 20363, + 31150, 37300, 38584, 24801, 20102, 20698, 23534, 23615, 26009, 29134, 30274, 34044, + 36988, 26248, 38446, 21129, 26491, 26611, 27969, 28316, 29705, 30041, 30827, 32016, + 39006, 25134, 38520, 20523, 23833, 28138, 36650, 24459, 24900, 26647, 38534, 21033, + 21519, 23653, 26131, 26446, 26792, 27877, 29702, 30178, 32633, 35023, 35041, 38626, + 21311, 28346, 21533, 29136, 29848, 34298, 38563, 40023, 40607, 26519, 28107, 33256, + 31520, 31890, 29376, 28825, 35672, 20160, 33590, 21050, 20999, 24230, 25299, 31958, + 23429, 27934, 26292, 36667, 38477, 24275, 20800, 21952, 22618, 26228, 20958, 29482, + 30410, 31036, 31070, 31077, 31119, 38742, 31934, 34322, 35576, 36920, 37117, 39151, + 39164, 39208, 40372, 37086, 38583, 20398, 20711, 20813, 21193, 21220, 21329, 21917, + 22022, 22120, 22592, 22696, 23652, 24724, 24936, 24974, 25074, 25935, 26082, 26257, + 26757, 28023, 28186, 28450, 29038, 29227, 29730, 30865, 31049, 31048, 31056, 31062, + 31117, 31118, 31296, 31361, 31680, 32265, 32321, 32626, 32773, 33261, 33401, 33879, + 35088, 35222, 35585, 35641, 36051, 36104, 36790, 38627, 38911, 38971, 24693, 148206, + 33304, 20006, 20917, 20840, 20352, 20805, 20864, 21191, 21242, 21845, 21913, 21986, + 22707, 22852, 22868, 23138, 23336, 24274, 24281, 24425, 24493, 24792, 24910, 24840, + 24928, 25140, 25540, 25628, 25682, 25942, 26395, 26454, 28379, 28363, 28702, 30631, + 29237, 29359, 29809, 29958, 30011, 30237, 30239, 30427, 30452, 30538, 30528, 30924, + 31409, 31867, 32091, 32574, 33618, 33775, 34681, 35137, 35206, 35519, 35531, 35565, + 35722, 36664, 36978, 37273, 37494, 38524, 38875, 38923, 39698, 141386, 141380, 144341, + 15261, 16408, 16441, 152137, 154832, 163539, 40771, 40846, 102, 102, 102, 105, 102, + 108, 102, 102, 108, 1396, 1398, 1396, 1381, 1396, 1387, 1406, 1398, 1396, 1389, + 1497, 1460, 1522, 1463, 1506, 1492, 1499, 1500, 1501, 1512, 1514, 1513, 1473, 1513, + 1474, 1513, 1468, 1473, 1513, 1468, 1474, 1488, 1463, 1488, 1464, 1488, 1468, 1489, + 1468, 1490, 1468, 1491, 1468, 1492, 1468, 1493, 1468, 1494, 1468, 1496, 1468, 1497, + 1468, 1498, 1468, 1499, 1468, 1500, 1468, 1502, 1468, 1504, 1468, 1505, 1468, 1507, + 1468, 1508, 1468, 1510, 1468, 1511, 1468, 1512, 1468, 1514, 1468, 1493, 1465, 1489, + 1471, 1499, 1471, 1508, 1471, 1488, 1500, 1649, 1659, 1662, 1664, 1658, 1663, 1657, + 1700, 1702, 1668, 1667, 1670, 1671, 1677, 1676, 1678, 1672, 1688, 1681, 1705, 1711, + 1715, 1713, 1722, 1723, 1728, 1729, 1726, 1746, 1747, 1709, 1734, 1736, 1739, 1733, + 1737, 1744, 1609, 1574, 1575, 1574, 1749, 1574, 1608, 1574, 1735, 1574, 1734, 1574, + 1736, 1574, 1744, 1574, 1609, 1740, 1574, 1580, 1574, 1581, 1574, 1605, 1574, 1610, + 1576, 1580, 1576, 1581, 1576, 1582, 1576, 1605, 1576, 1609, 1576, 1610, 1578, 1580, + 1578, 1581, 1578, 1582, 1578, 1605, 1578, 1609, 1578, 1610, 1579, 1580, 1579, 1605, + 1579, 1609, 1579, 1610, 1580, 1581, 1580, 1605, 1581, 1605, 1582, 1580, 1582, 1581, + 1582, 1605, 1587, 1580, 1587, 1581, 1587, 1582, 1587, 1605, 1589, 1581, 1589, 1605, + 1590, 1580, 1590, 1581, 1590, 1582, 1590, 1605, 1591, 1581, 1591, 1605, 1592, 1605, + 1593, 1580, 1593, 1605, 1594, 1580, 1594, 1605, 1601, 1580, 1601, 1581, 1601, 1582, + 1601, 1605, 1601, 1609, 1601, 1610, 1602, 1581, 1602, 1605, 1602, 1609, 1602, 1610, + 1603, 1575, 1603, 1580, 1603, 1581, 1603, 1582, 1603, 1604, 1603, 1605, 1603, 1609, + 1603, 1610, 1604, 1580, 1604, 1581, 1604, 1582, 1604, 1605, 1604, 1609, 1604, 1610, + 1605, 1580, 1605, 1605, 1605, 1609, 1605, 1610, 1606, 1580, 1606, 1581, 1606, 1582, + 1606, 1605, 1606, 1609, 1606, 1610, 1607, 1580, 1607, 1605, 1607, 1609, 1607, 1610, + 1610, 1581, 1610, 1582, 1610, 1609, 1584, 1648, 1585, 1648, 1609, 1648, 32, 1612, + 1617, 32, 1613, 1617, 32, 1614, 1617, 32, 1615, 1617, 32, 1616, 1617, 32, 1617, + 1648, 1574, 1585, 1574, 1586, 1574, 1606, 1576, 1585, 1576, 1586, 1576, 1606, 1578, + 1585, 1578, 1586, 1578, 1606, 1579, 1585, 1579, 1586, 1579, 1606, 1605, 1575, 1606, + 1585, 1606, 1586, 1606, 1606, 1610, 1585, 1610, 1586, 1574, 1582, 1574, 1607, 1576, + 1607, 1578, 1607, 1589, 1582, 1604, 1607, 1606, 1607, 1607, 1648, 1579, 1607, 1587, + 1607, 1588, 1605, 1588, 1607, 1600, 1614, 1617, 1600, 1615, 1617, 1600, 1616, 1617, + 1591, 1609, 1591, 1610, 1593, 1609, 1593, 1610, 1594, 1609, 1594, 1610, 1587, 1609, + 1587, 1610, 1588, 1609, 1588, 1610, 1581, 1609, 1580, 1609, 1580, 1610, 1582, 1609, + 1589, 1609, 1589, 1610, 1590, 1609, 1590, 1610, 1588, 1580, 1588, 1581, 1588, 1582, + 1588, 1585, 1587, 1585, 1589, 1585, 1590, 1585, 1575, 1611, 1578, 1580, 1605, 1578, + 1581, 1580, 1578, 1581, 1605, 1578, 1582, 1605, 1578, 1605, 1580, 1578, 1605, 1581, + 1578, 1605, 1582, 1581, 1605, 1610, 1581, 1605, 1609, 1587, 1581, 1580, 1587, 1580, + 1581, 1587, 1580, 1609, 1587, 1605, 1581, 1587, 1605, 1580, 1587, 1605, 1605, 1589, + 1581, 1581, 1589, 1605, 1605, 1588, 1581, 1605, 1588, 1580, 1610, 1588, 1605, 1582, + 1588, 1605, 1605, 1590, 1581, 1609, 1590, 1582, 1605, 1591, 1605, 1581, 1591, 1605, + 1605, 1591, 1605, 1610, 1593, 1580, 1605, 1593, 1605, 1605, 1593, 1605, 1609, 1594, + 1605, 1605, 1594, 1605, 1610, 1594, 1605, 1609, 1601, 1582, 1605, 1602, 1605, 1581, + 1602, 1605, 1605, 1604, 1581, 1605, 1604, 1581, 1610, 1604, 1581, 1609, 1604, 1580, + 1580, 1604, 1582, 1605, 1604, 1605, 1581, 1605, 1581, 1580, 1605, 1581, 1610, 1605, + 1580, 1581, 1605, 1582, 1605, 1605, 1580, 1582, 1607, 1605, 1580, 1607, 1605, 1605, + 1606, 1581, 1605, 1606, 1581, 1609, 1606, 1580, 1605, 1606, 1580, 1609, 1606, 1605, + 1610, 1606, 1605, 1609, 1610, 1605, 1605, 1576, 1582, 1610, 1578, 1580, 1610, 1578, + 1580, 1609, 1578, 1582, 1610, 1578, 1582, 1609, 1578, 1605, 1610, 1578, 1605, 1609, + 1580, 1605, 1610, 1580, 1581, 1609, 1580, 1605, 1609, 1587, 1582, 1609, 1589, 1581, + 1610, 1588, 1581, 1610, 1590, 1581, 1610, 1604, 1580, 1610, 1604, 1605, 1610, 1610, + 1580, 1610, 1610, 1605, 1610, 1605, 1605, 1610, 1602, 1605, 1610, 1606, 1581, 1610, + 1593, 1605, 1610, 1603, 1605, 1610, 1606, 1580, 1581, 1605, 1582, 1610, 1604, 1580, + 1605, 1603, 1605, 1605, 1580, 1581, 1610, 1581, 1580, 1610, 1605, 1580, 1610, 1601, + 1605, 1610, 1576, 1581, 1610, 1587, 1582, 1610, 1606, 1580, 1610, 1589, 1604, 1746, + 1602, 1604, 1746, 1575, 1604, 1604, 1607, 1575, 1603, 1576, 1585, 1605, 1581, 1605, + 1583, 1589, 1604, 1593, 1605, 1585, 1587, 1608, 1604, 1593, 1604, 1610, 1607, 1608, + 1587, 1604, 1605, 1589, 1604, 1609, 1589, 1604, 1609, 32, 1575, 1604, 1604, 1607, + 32, 1593, 1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, 1580, 1604, 32, 1580, 1604, + 1575, 1604, 1607, 1585, 1740, 1575, 1604, 44, 12289, 12310, 12311, 8212, 8211, 95, + 123, 125, 12308, 12309, 12304, 12305, 12298, 12299, 12300, 12301, 12302, 12303, + 91, 93, 35, 38, 42, 45, 60, 62, 92, 36, 37, 64, 32, 1611, 1600, 1611, 1600, 1617, + 32, 1618, 1600, 1618, 1569, 1570, 1571, 1572, 1573, 1577, 1604, 1570, 1604, 1571, + 1604, 1573, 34, 39, 94, 124, 126, 10629, 10630, 12539, 12453, 12515, 162, 163, 172, + 166, 165, 8361, 9474, 8592, 8593, 8594, 8595, 9632, 9675, 66600, 66601, 66602, 66603, + 66604, 66605, 66606, 66607, 66608, 66609, 66610, 66611, 66612, 66613, 66614, 66615, + 66616, 66617, 66618, 66619, 66620, 66621, 66622, 66623, 66624, 66625, 66626, 66627, + 66628, 66629, 66630, 66631, 66632, 66633, 66634, 66635, 66636, 66637, 66638, 66639, + 66776, 66777, 66778, 66779, 66780, 66781, 66782, 66783, 66784, 66785, 66786, 66787, + 66788, 66789, 66790, 66791, 66792, 66793, 66794, 66795, 66796, 66797, 66798, 66799, + 66800, 66801, 66802, 66803, 66804, 66805, 66806, 66807, 66808, 66809, 66810, 66811, + 66967, 66968, 66969, 66970, 66971, 66972, 66973, 66974, 66975, 66976, 66977, 66979, + 66980, 66981, 66982, 66983, 66984, 66985, 66986, 66987, 66988, 66989, 66990, 66991, + 66992, 66993, 66995, 66996, 66997, 66998, 66999, 67000, 67001, 67003, 67004, 720, + 721, 665, 675, 43878, 677, 676, 7569, 600, 606, 681, 612, 610, 667, 668, 615, 644, + 682, 683, 122628, 42894, 622, 122629, 654, 122630, 630, 631, 634, 122632, 638, 680, + 678, 43879, 679, 11377, 655, 673, 674, 664, 448, 449, 450, 122634, 122654, 68800, + 68801, 68802, 68803, 68804, 68805, 68806, 68807, 68808, 68809, 68810, 68811, 68812, + 68813, 68814, 68815, 68816, 68817, 68818, 68819, 68820, 68821, 68822, 68823, 68824, + 68825, 68826, 68827, 68828, 68829, 68830, 68831, 68832, 68833, 68834, 68835, 68836, + 68837, 68838, 68839, 68840, 68841, 68842, 68843, 68844, 68845, 68846, 68847, 68848, + 68849, 68850, 71872, 71873, 71874, 71875, 71876, 71877, 71878, 71879, 71880, 71881, + 71882, 71883, 71884, 71885, 71886, 71887, 71888, 71889, 71890, 71891, 71892, 71893, + 71894, 71895, 71896, 71897, 71898, 71899, 71900, 71901, 71902, 71903, 93792, 93793, + 93794, 93795, 93796, 93797, 93798, 93799, 93800, 93801, 93802, 93803, 93804, 93805, + 93806, 93807, 93808, 93809, 93810, 93811, 93812, 93813, 93814, 93815, 93816, 93817, + 93818, 93819, 93820, 93821, 93822, 93823, 119127, 119141, 119128, 119141, 119128, + 119141, 119150, 119128, 119141, 119151, 119128, 119141, 119152, 119128, 119141, + 119153, 119128, 119141, 119154, 119225, 119141, 119226, 119141, 119225, 119141, + 119150, 119226, 119141, 119150, 119225, 119141, 119151, 119226, 119141, 119151, + 305, 567, 8711, 8706, 1231, 125218, 125219, 125220, 125221, 125222, 125223, 125224, + 125225, 125226, 125227, 125228, 125229, 125230, 125231, 125232, 125233, 125234, + 125235, 125236, 125237, 125238, 125239, 125240, 125241, 125242, 125243, 125244, + 125245, 125246, 125247, 125248, 125249, 125250, 125251, 1646, 1697, 1647, 48, 44, + 49, 44, 50, 44, 51, 44, 52, 44, 53, 44, 54, 44, 55, 44, 56, 44, 57, 44, 12308, 115, + 12309, 119, 122, 104, 118, 115, 100, 115, 115, 112, 112, 118, 119, 99, 109, 114, + 100, 106, 12411, 12363, 12467, 12467, 23383, 21452, 22810, 35299, 20132, 26144, + 28961, 21069, 24460, 20877, 26032, 21021, 32066, 36009, 22768, 21561, 28436, 25237, + 25429, 36938, 25351, 25171, 31105, 31354, 21512, 28288, 30003, 21106, 21942, 37197, + 12308, 26412, 12309, 12308, 19977, 12309, 12308, 20108, 12309, 12308, 23433, 12309, + 12308, 28857, 12309, 12308, 25171, 12309, 12308, 30423, 12309, 12308, 21213, 12309, + 12308, 25943, 12309, 24471, 21487, 20029, 20024, 20033, 131362, 20320, 20411, 20482, + 20602, 20633, 20687, 13470, 132666, 20820, 20836, 20855, 132380, 13497, 20839, 132427, + 20887, 20900, 20172, 20908, 168415, 20995, 13535, 21051, 21062, 21111, 13589, 21253, + 21254, 21321, 21338, 21363, 21373, 21375, 133676, 28784, 21450, 21471, 133987, 21483, + 21489, 21510, 21662, 21560, 21576, 21608, 21666, 21750, 21776, 21843, 21859, 21892, + 21931, 21939, 21954, 22294, 22295, 22097, 22132, 22766, 22478, 22516, 22541, 22411, + 22578, 22577, 22700, 136420, 22770, 22775, 22790, 22818, 22882, 136872, 136938, + 23020, 23067, 23079, 23000, 23142, 14062, 23304, 23358, 137672, 23491, 23512, 23539, + 138008, 23551, 23558, 14209, 23648, 23744, 23693, 138724, 23875, 138726, 23918, + 23915, 23932, 24033, 24034, 14383, 24061, 24104, 24125, 24169, 14434, 139651, 14460, + 24240, 24243, 24246, 172946, 140081, 33281, 24354, 14535, 144056, 156122, 24418, + 24427, 14563, 24474, 24525, 24535, 24569, 24705, 14650, 14620, 141012, 24775, 24904, + 24908, 24954, 25010, 24996, 25007, 25054, 25115, 25181, 25265, 25300, 25424, 142092, + 25405, 25340, 25448, 25475, 25572, 142321, 25634, 25541, 25513, 14894, 25705, 25726, + 25757, 25719, 14956, 25964, 143370, 26083, 26360, 26185, 15129, 15112, 15076, 20882, + 20885, 26368, 26268, 32941, 17369, 26401, 26462, 26451, 144323, 15177, 26618, 26501, + 26706, 144493, 26766, 26655, 26900, 26946, 27043, 27114, 27304, 145059, 27355, 15384, + 27425, 145575, 27476, 15438, 27506, 27551, 27579, 146061, 138507, 146170, 27726, + 146620, 27839, 27853, 27751, 27926, 27966, 28009, 28024, 28037, 146718, 27956, 28207, + 28270, 15667, 28359, 147153, 28153, 28526, 147294, 147342, 28614, 28729, 28699, + 15766, 28746, 28797, 28791, 28845, 132389, 28997, 148067, 29084, 29224, 29264, 149000, + 29312, 29333, 149301, 149524, 29562, 29579, 16044, 29605, 16056, 29767, 29788, 29829, + 29898, 16155, 29988, 150582, 30014, 150674, 139679, 30224, 151457, 151480, 151620, + 16380, 16392, 151795, 151794, 151833, 151859, 30494, 30495, 30603, 16454, 16534, + 152605, 30798, 16611, 153126, 153242, 153285, 31211, 16687, 31306, 31311, 153980, + 154279, 16898, 154539, 31686, 31689, 16935, 154752, 31954, 17056, 31976, 31971, + 32000, 155526, 32099, 17153, 32199, 32258, 32325, 17204, 156200, 156231, 17241, + 156377, 32634, 156478, 32661, 32762, 156890, 156963, 32864, 157096, 32880, 144223, + 17365, 32946, 33027, 17419, 33086, 23221, 157607, 157621, 144275, 144284, 33284, + 36766, 17515, 33425, 33419, 33437, 21171, 33457, 33459, 33469, 33510, 158524, 33565, + 33635, 33709, 33571, 33725, 33767, 33619, 33738, 33740, 33756, 158774, 159083, 158933, + 17707, 34033, 34035, 34070, 160714, 34148, 159532, 17757, 17761, 159665, 159954, + 17771, 34384, 34407, 34409, 34473, 34440, 34574, 34530, 34600, 34667, 34694, 34785, + 34817, 17913, 34912, 161383, 35031, 35038, 17973, 35066, 13499, 161966, 162150, + 18110, 18119, 35488, 162984, 36011, 36033, 36123, 36215, 163631, 133124, 36299, + 36284, 36336, 133342, 36564, 165330, 165357, 37012, 37105, 37137, 165678, 37147, + 37432, 37591, 37592, 37500, 37881, 37909, 166906, 38283, 18837, 38327, 167287, 18918, + 38595, 23986, 38691, 168261, 168474, 19054, 19062, 38880, 168970, 19122, 169110, + 38953, 169398, 39138, 19251, 39209, 39335, 39362, 39422, 19406, 170800, 40000, 40189, + 19662, 19693, 40295, 172238, 19704, 172293, 172558, 172689, 19798, 40702, 40709, + 40719, 40726, 173568, + +}; +const uint32_t table[8002][2] = +{ + {0, 1}, {65, 16777219}, {66, 16777475}, {67, 16777731}, + {68, 16777987}, {69, 16778243}, {70, 16778499}, {71, 16778755}, + {72, 16779011}, {73, 16779267}, {74, 16779523}, {75, 16779779}, + {76, 16780035}, {77, 16780291}, {78, 16780547}, {79, 16780803}, + {80, 16781059}, {81, 16781315}, {82, 16781571}, {83, 16781827}, + {84, 16782083}, {85, 16782339}, {86, 16782595}, {87, 16782851}, + {88, 16783107}, {89, 16783363}, {90, 16783619}, {91, 1}, + {128, 2}, {160, 16783875}, {161, 1}, {168, 33561347}, + {169, 1}, {170, 16777219}, {171, 1}, {173, 0}, + {174, 1}, {175, 33561859}, {176, 1}, {178, 16785155}, + {179, 16785411}, {180, 33562883}, {181, 16786179}, {182, 1}, + {184, 33563651}, {185, 16786947}, {186, 16780803}, {187, 1}, + {188, 50341635}, {189, 50342403}, {190, 50343171}, {191, 1}, + {192, 16789507}, {193, 16789763}, {194, 16790019}, {195, 16790275}, + {196, 16790531}, {197, 16790787}, {198, 16791043}, {199, 16791299}, + {200, 16791555}, {201, 16791811}, {202, 16792067}, {203, 16792323}, + {204, 16792579}, {205, 16792835}, {206, 16793091}, {207, 16793347}, + {208, 16793603}, {209, 16793859}, {210, 16794115}, {211, 16794371}, + {212, 16794627}, {213, 16794883}, {214, 16795139}, {215, 1}, + {216, 16795395}, {217, 16795651}, {218, 16795907}, {219, 16796163}, + {220, 16796419}, {221, 16796675}, {222, 16796931}, {223, 1}, + {256, 16797187}, {257, 1}, {258, 16797443}, {259, 1}, + {260, 16797699}, {261, 1}, {262, 16797955}, {263, 1}, + {264, 16798211}, {265, 1}, {266, 16798467}, {267, 1}, + {268, 16798723}, {269, 1}, {270, 16798979}, {271, 1}, + {272, 16799235}, {273, 1}, {274, 16799491}, {275, 1}, + {276, 16799747}, {277, 1}, {278, 16800003}, {279, 1}, + {280, 16800259}, {281, 1}, {282, 16800515}, {283, 1}, + {284, 16800771}, {285, 1}, {286, 16801027}, {287, 1}, + {288, 16801283}, {289, 1}, {290, 16801539}, {291, 1}, + {292, 16801795}, {293, 1}, {294, 16802051}, {295, 1}, + {296, 16802307}, {297, 1}, {298, 16802563}, {299, 1}, + {300, 16802819}, {301, 1}, {302, 16803075}, {303, 1}, + {304, 33580547}, {305, 1}, {306, 33556483}, {308, 16803843}, + {309, 1}, {310, 16804099}, {311, 1}, {313, 16804355}, + {314, 1}, {315, 16804611}, {316, 1}, {317, 16804867}, + {318, 1}, {319, 33582339}, {321, 16805635}, {322, 1}, + {323, 16805891}, {324, 1}, {325, 16806147}, {326, 1}, + {327, 16806403}, {328, 1}, {329, 33583875}, {330, 16807171}, + {331, 1}, {332, 16807427}, {333, 1}, {334, 16807683}, + {335, 1}, {336, 16807939}, {337, 1}, {338, 16808195}, + {339, 1}, {340, 16808451}, {341, 1}, {342, 16808707}, + {343, 1}, {344, 16808963}, {345, 1}, {346, 16809219}, + {347, 1}, {348, 16809475}, {349, 1}, {350, 16809731}, + {351, 1}, {352, 16809987}, {353, 1}, {354, 16810243}, + {355, 1}, {356, 16810499}, {357, 1}, {358, 16810755}, + {359, 1}, {360, 16811011}, {361, 1}, {362, 16811267}, + {363, 1}, {364, 16811523}, {365, 1}, {366, 16811779}, + {367, 1}, {368, 16812035}, {369, 1}, {370, 16812291}, + {371, 1}, {372, 16812547}, {373, 1}, {374, 16812803}, + {375, 1}, {376, 16813059}, {377, 16813315}, {378, 1}, + {379, 16813571}, {380, 1}, {381, 16813827}, {382, 1}, + {383, 16781827}, {384, 1}, {385, 16814083}, {386, 16814339}, + {387, 1}, {388, 16814595}, {389, 1}, {390, 16814851}, + {391, 16815107}, {392, 1}, {393, 16815363}, {394, 16815619}, + {395, 16815875}, {396, 1}, {398, 16816131}, {399, 16816387}, + {400, 16816643}, {401, 16816899}, {402, 1}, {403, 16817155}, + {404, 16817411}, {405, 1}, {406, 16817667}, {407, 16817923}, + {408, 16818179}, {409, 1}, {412, 16818435}, {413, 16818691}, + {414, 1}, {415, 16818947}, {416, 16819203}, {417, 1}, + {418, 16819459}, {419, 1}, {420, 16819715}, {421, 1}, + {422, 16819971}, {423, 16820227}, {424, 1}, {425, 16820483}, + {426, 1}, {428, 16820739}, {429, 1}, {430, 16820995}, + {431, 16821251}, {432, 1}, {433, 16821507}, {434, 16821763}, + {435, 16822019}, {436, 1}, {437, 16822275}, {438, 1}, + {439, 16822531}, {440, 16822787}, {441, 1}, {444, 16823043}, + {445, 1}, {452, 33600515}, {455, 33601027}, {458, 33601539}, + {461, 16824835}, {462, 1}, {463, 16825091}, {464, 1}, + {465, 16825347}, {466, 1}, {467, 16825603}, {468, 1}, + {469, 16825859}, {470, 1}, {471, 16826115}, {472, 1}, + {473, 16826371}, {474, 1}, {475, 16826627}, {476, 1}, + {478, 16826883}, {479, 1}, {480, 16827139}, {481, 1}, + {482, 16827395}, {483, 1}, {484, 16827651}, {485, 1}, + {486, 16827907}, {487, 1}, {488, 16828163}, {489, 1}, + {490, 16828419}, {491, 1}, {492, 16828675}, {493, 1}, + {494, 16828931}, {495, 1}, {497, 33606403}, {500, 16829699}, + {501, 1}, {502, 16829955}, {503, 16830211}, {504, 16830467}, + {505, 1}, {506, 16830723}, {507, 1}, {508, 16830979}, + {509, 1}, {510, 16831235}, {511, 1}, {512, 16831491}, + {513, 1}, {514, 16831747}, {515, 1}, {516, 16832003}, + {517, 1}, {518, 16832259}, {519, 1}, {520, 16832515}, + {521, 1}, {522, 16832771}, {523, 1}, {524, 16833027}, + {525, 1}, {526, 16833283}, {527, 1}, {528, 16833539}, + {529, 1}, {530, 16833795}, {531, 1}, {532, 16834051}, + {533, 1}, {534, 16834307}, {535, 1}, {536, 16834563}, + {537, 1}, {538, 16834819}, {539, 1}, {540, 16835075}, + {541, 1}, {542, 16835331}, {543, 1}, {544, 16835587}, + {545, 1}, {546, 16835843}, {547, 1}, {548, 16836099}, + {549, 1}, {550, 16836355}, {551, 1}, {552, 16836611}, + {553, 1}, {554, 16836867}, {555, 1}, {556, 16837123}, + {557, 1}, {558, 16837379}, {559, 1}, {560, 16837635}, + {561, 1}, {562, 16837891}, {563, 1}, {570, 16838147}, + {571, 16838403}, {572, 1}, {573, 16838659}, {574, 16838915}, + {575, 1}, {577, 16839171}, {578, 1}, {579, 16839427}, + {580, 16839683}, {581, 16839939}, {582, 16840195}, {583, 1}, + {584, 16840451}, {585, 1}, {586, 16840707}, {587, 1}, + {588, 16840963}, {589, 1}, {590, 16841219}, {591, 1}, + {688, 16779011}, {689, 16841475}, {690, 16779523}, {691, 16781571}, + {692, 16841731}, {693, 16841987}, {694, 16842243}, {695, 16782851}, + {696, 16783363}, {697, 1}, {728, 33619715}, {729, 33620227}, + {730, 33620739}, {731, 33621251}, {732, 33621763}, {733, 33622275}, + {734, 1}, {736, 16817411}, {737, 16780035}, {738, 16781827}, + {739, 16783107}, {740, 16845571}, {741, 1}, {832, 16845827}, + {833, 16785923}, {834, 1}, {835, 16846083}, {836, 33623555}, + {837, 16846851}, {838, 1}, {847, 0}, {848, 1}, + {880, 16847107}, {881, 1}, {882, 16847363}, {883, 1}, + {884, 16847619}, {885, 1}, {886, 16847875}, {887, 1}, + {888, 2}, {890, 33625347}, {891, 1}, {894, 16848643}, + {895, 16848899}, {896, 2}, {900, 33562883}, {901, 50403587}, + {902, 16849923}, {903, 16805379}, {904, 16850179}, {905, 16850435}, + {906, 16850691}, {907, 2}, {908, 16850947}, {909, 2}, + {910, 16851203}, {911, 16851459}, {912, 1}, {913, 16851715}, + {914, 16851971}, {915, 16852227}, {916, 16852483}, {917, 16852739}, + {918, 16852995}, {919, 16853251}, {920, 16853507}, {921, 16846851}, + {922, 16853763}, {923, 16854019}, {924, 16786179}, {925, 16854275}, + {926, 16854531}, {927, 16854787}, {928, 16855043}, {929, 16855299}, + {930, 2}, {931, 16855555}, {932, 16855811}, {933, 16856067}, + {934, 16856323}, {935, 16856579}, {936, 16856835}, {937, 16857091}, + {938, 16857347}, {939, 16857603}, {940, 1}, {975, 16857859}, + {976, 16851971}, {977, 16853507}, {978, 16856067}, {979, 16851203}, + {980, 16857603}, {981, 16856323}, {982, 16855043}, {983, 1}, + {984, 16858115}, {985, 1}, {986, 16858371}, {987, 1}, + {988, 16858627}, {989, 1}, {990, 16858883}, {991, 1}, + {992, 16859139}, {993, 1}, {994, 16859395}, {995, 1}, + {996, 16859651}, {997, 1}, {998, 16859907}, {999, 1}, + {1000, 16860163}, {1001, 1}, {1002, 16860419}, {1003, 1}, + {1004, 16860675}, {1005, 1}, {1006, 16860931}, {1007, 1}, + {1008, 16853763}, {1009, 16855299}, {1010, 16855555}, {1011, 1}, + {1012, 16853507}, {1013, 16852739}, {1014, 1}, {1015, 16861187}, + {1016, 1}, {1017, 16855555}, {1018, 16861443}, {1019, 1}, + {1021, 16861699}, {1022, 16861955}, {1023, 16862211}, {1024, 16862467}, + {1025, 16862723}, {1026, 16862979}, {1027, 16863235}, {1028, 16863491}, + {1029, 16863747}, {1030, 16864003}, {1031, 16864259}, {1032, 16864515}, + {1033, 16864771}, {1034, 16865027}, {1035, 16865283}, {1036, 16865539}, + {1037, 16865795}, {1038, 16866051}, {1039, 16866307}, {1040, 16866563}, + {1041, 16866819}, {1042, 16867075}, {1043, 16867331}, {1044, 16867587}, + {1045, 16867843}, {1046, 16868099}, {1047, 16868355}, {1048, 16868611}, + {1049, 16868867}, {1050, 16869123}, {1051, 16869379}, {1052, 16869635}, + {1053, 16869891}, {1054, 16870147}, {1055, 16870403}, {1056, 16870659}, + {1057, 16870915}, {1058, 16871171}, {1059, 16871427}, {1060, 16871683}, + {1061, 16871939}, {1062, 16872195}, {1063, 16872451}, {1064, 16872707}, + {1065, 16872963}, {1066, 16873219}, {1067, 16873475}, {1068, 16873731}, + {1069, 16873987}, {1070, 16874243}, {1071, 16874499}, {1072, 1}, + {1120, 16874755}, {1121, 1}, {1122, 16875011}, {1123, 1}, + {1124, 16875267}, {1125, 1}, {1126, 16875523}, {1127, 1}, + {1128, 16875779}, {1129, 1}, {1130, 16876035}, {1131, 1}, + {1132, 16876291}, {1133, 1}, {1134, 16876547}, {1135, 1}, + {1136, 16876803}, {1137, 1}, {1138, 16877059}, {1139, 1}, + {1140, 16877315}, {1141, 1}, {1142, 16877571}, {1143, 1}, + {1144, 16877827}, {1145, 1}, {1146, 16878083}, {1147, 1}, + {1148, 16878339}, {1149, 1}, {1150, 16878595}, {1151, 1}, + {1152, 16878851}, {1153, 1}, {1162, 16879107}, {1163, 1}, + {1164, 16879363}, {1165, 1}, {1166, 16879619}, {1167, 1}, + {1168, 16879875}, {1169, 1}, {1170, 16880131}, {1171, 1}, + {1172, 16880387}, {1173, 1}, {1174, 16880643}, {1175, 1}, + {1176, 16880899}, {1177, 1}, {1178, 16881155}, {1179, 1}, + {1180, 16881411}, {1181, 1}, {1182, 16881667}, {1183, 1}, + {1184, 16881923}, {1185, 1}, {1186, 16882179}, {1187, 1}, + {1188, 16882435}, {1189, 1}, {1190, 16882691}, {1191, 1}, + {1192, 16882947}, {1193, 1}, {1194, 16883203}, {1195, 1}, + {1196, 16883459}, {1197, 1}, {1198, 16883715}, {1199, 1}, + {1200, 16883971}, {1201, 1}, {1202, 16884227}, {1203, 1}, + {1204, 16884483}, {1205, 1}, {1206, 16884739}, {1207, 1}, + {1208, 16884995}, {1209, 1}, {1210, 16885251}, {1211, 1}, + {1212, 16885507}, {1213, 1}, {1214, 16885763}, {1215, 1}, + {1216, 2}, {1217, 16886019}, {1218, 1}, {1219, 16886275}, + {1220, 1}, {1221, 16886531}, {1222, 1}, {1223, 16886787}, + {1224, 1}, {1225, 16887043}, {1226, 1}, {1227, 16887299}, + {1228, 1}, {1229, 16887555}, {1230, 1}, {1232, 16887811}, + {1233, 1}, {1234, 16888067}, {1235, 1}, {1236, 16888323}, + {1237, 1}, {1238, 16888579}, {1239, 1}, {1240, 16888835}, + {1241, 1}, {1242, 16889091}, {1243, 1}, {1244, 16889347}, + {1245, 1}, {1246, 16889603}, {1247, 1}, {1248, 16889859}, + {1249, 1}, {1250, 16890115}, {1251, 1}, {1252, 16890371}, + {1253, 1}, {1254, 16890627}, {1255, 1}, {1256, 16890883}, + {1257, 1}, {1258, 16891139}, {1259, 1}, {1260, 16891395}, + {1261, 1}, {1262, 16891651}, {1263, 1}, {1264, 16891907}, + {1265, 1}, {1266, 16892163}, {1267, 1}, {1268, 16892419}, + {1269, 1}, {1270, 16892675}, {1271, 1}, {1272, 16892931}, + {1273, 1}, {1274, 16893187}, {1275, 1}, {1276, 16893443}, + {1277, 1}, {1278, 16893699}, {1279, 1}, {1280, 16893955}, + {1281, 1}, {1282, 16894211}, {1283, 1}, {1284, 16894467}, + {1285, 1}, {1286, 16894723}, {1287, 1}, {1288, 16894979}, + {1289, 1}, {1290, 16895235}, {1291, 1}, {1292, 16895491}, + {1293, 1}, {1294, 16895747}, {1295, 1}, {1296, 16896003}, + {1297, 1}, {1298, 16896259}, {1299, 1}, {1300, 16896515}, + {1301, 1}, {1302, 16896771}, {1303, 1}, {1304, 16897027}, + {1305, 1}, {1306, 16897283}, {1307, 1}, {1308, 16897539}, + {1309, 1}, {1310, 16897795}, {1311, 1}, {1312, 16898051}, + {1313, 1}, {1314, 16898307}, {1315, 1}, {1316, 16898563}, + {1317, 1}, {1318, 16898819}, {1319, 1}, {1320, 16899075}, + {1321, 1}, {1322, 16899331}, {1323, 1}, {1324, 16899587}, + {1325, 1}, {1326, 16899843}, {1327, 1}, {1328, 2}, + {1329, 16900099}, {1330, 16900355}, {1331, 16900611}, {1332, 16900867}, + {1333, 16901123}, {1334, 16901379}, {1335, 16901635}, {1336, 16901891}, + {1337, 16902147}, {1338, 16902403}, {1339, 16902659}, {1340, 16902915}, + {1341, 16903171}, {1342, 16903427}, {1343, 16903683}, {1344, 16903939}, + {1345, 16904195}, {1346, 16904451}, {1347, 16904707}, {1348, 16904963}, + {1349, 16905219}, {1350, 16905475}, {1351, 16905731}, {1352, 16905987}, + {1353, 16906243}, {1354, 16906499}, {1355, 16906755}, {1356, 16907011}, + {1357, 16907267}, {1358, 16907523}, {1359, 16907779}, {1360, 16908035}, + {1361, 16908291}, {1362, 16908547}, {1363, 16908803}, {1364, 16909059}, + {1365, 16909315}, {1366, 16909571}, {1367, 2}, {1369, 1}, + {1415, 33687043}, {1416, 1}, {1419, 2}, {1421, 1}, + {1424, 2}, {1425, 1}, {1480, 2}, {1488, 1}, + {1515, 2}, {1519, 1}, {1525, 2}, {1542, 1}, + {1564, 2}, {1565, 1}, {1653, 33687555}, {1654, 33688067}, + {1655, 33688579}, {1656, 33689091}, {1657, 1}, {1757, 2}, + {1758, 1}, {1806, 2}, {1808, 1}, {1867, 2}, + {1869, 1}, {1970, 2}, {1984, 1}, {2043, 2}, + {2045, 1}, {2094, 2}, {2096, 1}, {2111, 2}, + {2112, 1}, {2140, 2}, {2142, 1}, {2143, 2}, + {2144, 1}, {2155, 2}, {2160, 1}, {2191, 2}, + {2200, 1}, {2274, 2}, {2275, 1}, {2392, 33689603}, + {2393, 33690115}, {2394, 33690627}, {2395, 33691139}, {2396, 33691651}, + {2397, 33692163}, {2398, 33692675}, {2399, 33693187}, {2400, 1}, + {2436, 2}, {2437, 1}, {2445, 2}, {2447, 1}, + {2449, 2}, {2451, 1}, {2473, 2}, {2474, 1}, + {2481, 2}, {2482, 1}, {2483, 2}, {2486, 1}, + {2490, 2}, {2492, 1}, {2501, 2}, {2503, 1}, + {2505, 2}, {2507, 1}, {2511, 2}, {2519, 1}, + {2520, 2}, {2524, 33693699}, {2525, 33694211}, {2526, 2}, + {2527, 33694723}, {2528, 1}, {2532, 2}, {2534, 1}, + {2559, 2}, {2561, 1}, {2564, 2}, {2565, 1}, + {2571, 2}, {2575, 1}, {2577, 2}, {2579, 1}, + {2601, 2}, {2602, 1}, {2609, 2}, {2610, 1}, + {2611, 33695235}, {2612, 2}, {2613, 1}, {2614, 33695747}, + {2615, 2}, {2616, 1}, {2618, 2}, {2620, 1}, + {2621, 2}, {2622, 1}, {2627, 2}, {2631, 1}, + {2633, 2}, {2635, 1}, {2638, 2}, {2641, 1}, + {2642, 2}, {2649, 33696259}, {2650, 33696771}, {2651, 33697283}, + {2652, 1}, {2653, 2}, {2654, 33697795}, {2655, 2}, + {2662, 1}, {2679, 2}, {2689, 1}, {2692, 2}, + {2693, 1}, {2702, 2}, {2703, 1}, {2706, 2}, + {2707, 1}, {2729, 2}, {2730, 1}, {2737, 2}, + {2738, 1}, {2740, 2}, {2741, 1}, {2746, 2}, + {2748, 1}, {2758, 2}, {2759, 1}, {2762, 2}, + {2763, 1}, {2766, 2}, {2768, 1}, {2769, 2}, + {2784, 1}, {2788, 2}, {2790, 1}, {2802, 2}, + {2809, 1}, {2816, 2}, {2817, 1}, {2820, 2}, + {2821, 1}, {2829, 2}, {2831, 1}, {2833, 2}, + {2835, 1}, {2857, 2}, {2858, 1}, {2865, 2}, + {2866, 1}, {2868, 2}, {2869, 1}, {2874, 2}, + {2876, 1}, {2885, 2}, {2887, 1}, {2889, 2}, + {2891, 1}, {2894, 2}, {2901, 1}, {2904, 2}, + {2908, 33698307}, {2909, 33698819}, {2910, 2}, {2911, 1}, + {2916, 2}, {2918, 1}, {2936, 2}, {2946, 1}, + {2948, 2}, {2949, 1}, {2955, 2}, {2958, 1}, + {2961, 2}, {2962, 1}, {2966, 2}, {2969, 1}, + {2971, 2}, {2972, 1}, {2973, 2}, {2974, 1}, + {2976, 2}, {2979, 1}, {2981, 2}, {2984, 1}, + {2987, 2}, {2990, 1}, {3002, 2}, {3006, 1}, + {3011, 2}, {3014, 1}, {3017, 2}, {3018, 1}, + {3022, 2}, {3024, 1}, {3025, 2}, {3031, 1}, + {3032, 2}, {3046, 1}, {3067, 2}, {3072, 1}, + {3085, 2}, {3086, 1}, {3089, 2}, {3090, 1}, + {3113, 2}, {3114, 1}, {3130, 2}, {3132, 1}, + {3141, 2}, {3142, 1}, {3145, 2}, {3146, 1}, + {3150, 2}, {3157, 1}, {3159, 2}, {3160, 1}, + {3163, 2}, {3165, 1}, {3166, 2}, {3168, 1}, + {3172, 2}, {3174, 1}, {3184, 2}, {3191, 1}, + {3213, 2}, {3214, 1}, {3217, 2}, {3218, 1}, + {3241, 2}, {3242, 1}, {3252, 2}, {3253, 1}, + {3258, 2}, {3260, 1}, {3269, 2}, {3270, 1}, + {3273, 2}, {3274, 1}, {3278, 2}, {3285, 1}, + {3287, 2}, {3293, 1}, {3295, 2}, {3296, 1}, + {3300, 2}, {3302, 1}, {3312, 2}, {3313, 1}, + {3316, 2}, {3328, 1}, {3341, 2}, {3342, 1}, + {3345, 2}, {3346, 1}, {3397, 2}, {3398, 1}, + {3401, 2}, {3402, 1}, {3408, 2}, {3412, 1}, + {3428, 2}, {3430, 1}, {3456, 2}, {3457, 1}, + {3460, 2}, {3461, 1}, {3479, 2}, {3482, 1}, + {3506, 2}, {3507, 1}, {3516, 2}, {3517, 1}, + {3518, 2}, {3520, 1}, {3527, 2}, {3530, 1}, + {3531, 2}, {3535, 1}, {3541, 2}, {3542, 1}, + {3543, 2}, {3544, 1}, {3552, 2}, {3558, 1}, + {3568, 2}, {3570, 1}, {3573, 2}, {3585, 1}, + {3635, 33699331}, {3636, 1}, {3643, 2}, {3647, 1}, + {3676, 2}, {3713, 1}, {3715, 2}, {3716, 1}, + {3717, 2}, {3718, 1}, {3723, 2}, {3724, 1}, + {3748, 2}, {3749, 1}, {3750, 2}, {3751, 1}, + {3763, 33699843}, {3764, 1}, {3774, 2}, {3776, 1}, + {3781, 2}, {3782, 1}, {3783, 2}, {3784, 1}, + {3791, 2}, {3792, 1}, {3802, 2}, {3804, 33700355}, + {3805, 33700867}, {3806, 1}, {3808, 2}, {3840, 1}, + {3852, 16924163}, {3853, 1}, {3907, 33701635}, {3908, 1}, + {3912, 2}, {3913, 1}, {3917, 33702147}, {3918, 1}, + {3922, 33702659}, {3923, 1}, {3927, 33703171}, {3928, 1}, + {3932, 33703683}, {3933, 1}, {3945, 33704195}, {3946, 1}, + {3949, 2}, {3953, 1}, {3955, 33704707}, {3956, 1}, + {3957, 33705219}, {3958, 33705731}, {3959, 50483459}, {3960, 33707011}, + {3961, 50484739}, {3962, 1}, {3969, 33706499}, {3970, 1}, + {3987, 33708291}, {3988, 1}, {3992, 2}, {3993, 1}, + {3997, 33708803}, {3998, 1}, {4002, 33709315}, {4003, 1}, + {4007, 33709827}, {4008, 1}, {4012, 33710339}, {4013, 1}, + {4025, 33710851}, {4026, 1}, {4029, 2}, {4030, 1}, + {4045, 2}, {4046, 1}, {4059, 2}, {4096, 1}, + {4256, 2}, {4295, 16934147}, {4296, 2}, {4301, 16934403}, + {4302, 2}, {4304, 1}, {4348, 16934659}, {4349, 1}, + {4447, 2}, {4449, 1}, {4681, 2}, {4682, 1}, + {4686, 2}, {4688, 1}, {4695, 2}, {4696, 1}, + {4697, 2}, {4698, 1}, {4702, 2}, {4704, 1}, + {4745, 2}, {4746, 1}, {4750, 2}, {4752, 1}, + {4785, 2}, {4786, 1}, {4790, 2}, {4792, 1}, + {4799, 2}, {4800, 1}, {4801, 2}, {4802, 1}, + {4806, 2}, {4808, 1}, {4823, 2}, {4824, 1}, + {4881, 2}, {4882, 1}, {4886, 2}, {4888, 1}, + {4955, 2}, {4957, 1}, {4989, 2}, {4992, 1}, + {5018, 2}, {5024, 1}, {5110, 2}, {5112, 16934915}, + {5113, 16935171}, {5114, 16935427}, {5115, 16935683}, {5116, 16935939}, + {5117, 16936195}, {5118, 2}, {5120, 1}, {5760, 2}, + {5761, 1}, {5789, 2}, {5792, 1}, {5881, 2}, + {5888, 1}, {5910, 2}, {5919, 1}, {5943, 2}, + {5952, 1}, {5972, 2}, {5984, 1}, {5997, 2}, + {5998, 1}, {6001, 2}, {6002, 1}, {6004, 2}, + {6016, 1}, {6068, 2}, {6070, 1}, {6110, 2}, + {6112, 1}, {6122, 2}, {6128, 1}, {6138, 2}, + {6144, 1}, {6150, 2}, {6151, 1}, {6155, 0}, + {6158, 2}, {6159, 0}, {6160, 1}, {6170, 2}, + {6176, 1}, {6265, 2}, {6272, 1}, {6315, 2}, + {6320, 1}, {6390, 2}, {6400, 1}, {6431, 2}, + {6432, 1}, {6444, 2}, {6448, 1}, {6460, 2}, + {6464, 1}, {6465, 2}, {6468, 1}, {6510, 2}, + {6512, 1}, {6517, 2}, {6528, 1}, {6572, 2}, + {6576, 1}, {6602, 2}, {6608, 1}, {6619, 2}, + {6622, 1}, {6684, 2}, {6686, 1}, {6751, 2}, + {6752, 1}, {6781, 2}, {6783, 1}, {6794, 2}, + {6800, 1}, {6810, 2}, {6816, 1}, {6830, 2}, + {6832, 1}, {6863, 2}, {6912, 1}, {6989, 2}, + {6992, 1}, {7039, 2}, {7040, 1}, {7156, 2}, + {7164, 1}, {7224, 2}, {7227, 1}, {7242, 2}, + {7245, 1}, {7296, 16867075}, {7297, 16867587}, {7298, 16870147}, + {7299, 16870915}, {7300, 16871171}, {7302, 16873219}, {7303, 16875011}, + {7304, 16936451}, {7305, 2}, {7312, 16936707}, {7313, 16936963}, + {7314, 16937219}, {7315, 16937475}, {7316, 16937731}, {7317, 16937987}, + {7318, 16938243}, {7319, 16938499}, {7320, 16938755}, {7321, 16939011}, + {7322, 16939267}, {7323, 16939523}, {7324, 16934659}, {7325, 16939779}, + {7326, 16940035}, {7327, 16940291}, {7328, 16940547}, {7329, 16940803}, + {7330, 16941059}, {7331, 16941315}, {7332, 16941571}, {7333, 16941827}, + {7334, 16942083}, {7335, 16942339}, {7336, 16942595}, {7337, 16942851}, + {7338, 16943107}, {7339, 16943363}, {7340, 16943619}, {7341, 16943875}, + {7342, 16944131}, {7343, 16944387}, {7344, 16944643}, {7345, 16944899}, + {7346, 16945155}, {7347, 16945411}, {7348, 16945667}, {7349, 16945923}, + {7350, 16946179}, {7351, 16946435}, {7352, 16946691}, {7353, 16946947}, + {7354, 16947203}, {7355, 2}, {7357, 16947459}, {7358, 16947715}, + {7359, 16947971}, {7360, 1}, {7368, 2}, {7376, 1}, + {7419, 2}, {7424, 1}, {7468, 16777219}, {7469, 16791043}, + {7470, 16777475}, {7471, 1}, {7472, 16777987}, {7473, 16778243}, + {7474, 16816131}, {7475, 16778755}, {7476, 16779011}, {7477, 16779267}, + {7478, 16779523}, {7479, 16779779}, {7480, 16780035}, {7481, 16780291}, + {7482, 16780547}, {7483, 1}, {7484, 16780803}, {7485, 16835843}, + {7486, 16781059}, {7487, 16781571}, {7488, 16782083}, {7489, 16782339}, + {7490, 16782851}, {7491, 16777219}, {7492, 16948227}, {7493, 16948483}, + {7494, 16948739}, {7495, 16777475}, {7496, 16777987}, {7497, 16778243}, + {7498, 16816387}, {7499, 16816643}, {7500, 16948995}, {7501, 16778755}, + {7502, 1}, {7503, 16779779}, {7504, 16780291}, {7505, 16807171}, + {7506, 16780803}, {7507, 16814851}, {7508, 16949251}, {7509, 16949507}, + {7510, 16781059}, {7511, 16782083}, {7512, 16782339}, {7513, 16949763}, + {7514, 16818435}, {7515, 16782595}, {7516, 16950019}, {7517, 16851971}, + {7518, 16852227}, {7519, 16852483}, {7520, 16856323}, {7521, 16856579}, + {7522, 16779267}, {7523, 16781571}, {7524, 16782339}, {7525, 16782595}, + {7526, 16851971}, {7527, 16852227}, {7528, 16855299}, {7529, 16856323}, + {7530, 16856579}, {7531, 1}, {7544, 16869891}, {7545, 1}, + {7579, 16950275}, {7580, 16777731}, {7581, 16950531}, {7582, 16793603}, + {7583, 16948995}, {7584, 16778499}, {7585, 16950787}, {7586, 16951043}, + {7587, 16951299}, {7588, 16817923}, {7589, 16817667}, {7590, 16951555}, + {7591, 16951811}, {7592, 16952067}, {7593, 16952323}, {7594, 16952579}, + {7595, 16952835}, {7596, 16953091}, {7597, 16953347}, {7598, 16818691}, + {7599, 16953603}, {7600, 16953859}, {7601, 16818947}, {7602, 16954115}, + {7603, 16954371}, {7604, 16820483}, {7605, 16954627}, {7606, 16839683}, + {7607, 16821507}, {7608, 16954883}, {7609, 16821763}, {7610, 16839939}, + {7611, 16783619}, {7612, 16955139}, {7613, 16955395}, {7614, 16822531}, + {7615, 16853507}, {7616, 1}, {7680, 16955651}, {7681, 1}, + {7682, 16955907}, {7683, 1}, {7684, 16956163}, {7685, 1}, + {7686, 16956419}, {7687, 1}, {7688, 16956675}, {7689, 1}, + {7690, 16956931}, {7691, 1}, {7692, 16957187}, {7693, 1}, + {7694, 16957443}, {7695, 1}, {7696, 16957699}, {7697, 1}, + {7698, 16957955}, {7699, 1}, {7700, 16958211}, {7701, 1}, + {7702, 16958467}, {7703, 1}, {7704, 16958723}, {7705, 1}, + {7706, 16958979}, {7707, 1}, {7708, 16959235}, {7709, 1}, + {7710, 16959491}, {7711, 1}, {7712, 16959747}, {7713, 1}, + {7714, 16960003}, {7715, 1}, {7716, 16960259}, {7717, 1}, + {7718, 16960515}, {7719, 1}, {7720, 16960771}, {7721, 1}, + {7722, 16961027}, {7723, 1}, {7724, 16961283}, {7725, 1}, + {7726, 16961539}, {7727, 1}, {7728, 16961795}, {7729, 1}, + {7730, 16962051}, {7731, 1}, {7732, 16962307}, {7733, 1}, + {7734, 16962563}, {7735, 1}, {7736, 16962819}, {7737, 1}, + {7738, 16963075}, {7739, 1}, {7740, 16963331}, {7741, 1}, + {7742, 16963587}, {7743, 1}, {7744, 16963843}, {7745, 1}, + {7746, 16964099}, {7747, 1}, {7748, 16964355}, {7749, 1}, + {7750, 16964611}, {7751, 1}, {7752, 16964867}, {7753, 1}, + {7754, 16965123}, {7755, 1}, {7756, 16965379}, {7757, 1}, + {7758, 16965635}, {7759, 1}, {7760, 16965891}, {7761, 1}, + {7762, 16966147}, {7763, 1}, {7764, 16966403}, {7765, 1}, + {7766, 16966659}, {7767, 1}, {7768, 16966915}, {7769, 1}, + {7770, 16967171}, {7771, 1}, {7772, 16967427}, {7773, 1}, + {7774, 16967683}, {7775, 1}, {7776, 16967939}, {7777, 1}, + {7778, 16968195}, {7779, 1}, {7780, 16968451}, {7781, 1}, + {7782, 16968707}, {7783, 1}, {7784, 16968963}, {7785, 1}, + {7786, 16969219}, {7787, 1}, {7788, 16969475}, {7789, 1}, + {7790, 16969731}, {7791, 1}, {7792, 16969987}, {7793, 1}, + {7794, 16970243}, {7795, 1}, {7796, 16970499}, {7797, 1}, + {7798, 16970755}, {7799, 1}, {7800, 16971011}, {7801, 1}, + {7802, 16971267}, {7803, 1}, {7804, 16971523}, {7805, 1}, + {7806, 16971779}, {7807, 1}, {7808, 16972035}, {7809, 1}, + {7810, 16972291}, {7811, 1}, {7812, 16972547}, {7813, 1}, + {7814, 16972803}, {7815, 1}, {7816, 16973059}, {7817, 1}, + {7818, 16973315}, {7819, 1}, {7820, 16973571}, {7821, 1}, + {7822, 16973827}, {7823, 1}, {7824, 16974083}, {7825, 1}, + {7826, 16974339}, {7827, 1}, {7828, 16974595}, {7829, 1}, + {7834, 33752067}, {7835, 16967939}, {7836, 1}, {7838, 16975363}, + {7839, 1}, {7840, 16975619}, {7841, 1}, {7842, 16975875}, + {7843, 1}, {7844, 16976131}, {7845, 1}, {7846, 16976387}, + {7847, 1}, {7848, 16976643}, {7849, 1}, {7850, 16976899}, + {7851, 1}, {7852, 16977155}, {7853, 1}, {7854, 16977411}, + {7855, 1}, {7856, 16977667}, {7857, 1}, {7858, 16977923}, + {7859, 1}, {7860, 16978179}, {7861, 1}, {7862, 16978435}, + {7863, 1}, {7864, 16978691}, {7865, 1}, {7866, 16978947}, + {7867, 1}, {7868, 16979203}, {7869, 1}, {7870, 16979459}, + {7871, 1}, {7872, 16979715}, {7873, 1}, {7874, 16979971}, + {7875, 1}, {7876, 16980227}, {7877, 1}, {7878, 16980483}, + {7879, 1}, {7880, 16980739}, {7881, 1}, {7882, 16980995}, + {7883, 1}, {7884, 16981251}, {7885, 1}, {7886, 16981507}, + {7887, 1}, {7888, 16981763}, {7889, 1}, {7890, 16982019}, + {7891, 1}, {7892, 16982275}, {7893, 1}, {7894, 16982531}, + {7895, 1}, {7896, 16982787}, {7897, 1}, {7898, 16983043}, + {7899, 1}, {7900, 16983299}, {7901, 1}, {7902, 16983555}, + {7903, 1}, {7904, 16983811}, {7905, 1}, {7906, 16984067}, + {7907, 1}, {7908, 16984323}, {7909, 1}, {7910, 16984579}, + {7911, 1}, {7912, 16984835}, {7913, 1}, {7914, 16985091}, + {7915, 1}, {7916, 16985347}, {7917, 1}, {7918, 16985603}, + {7919, 1}, {7920, 16985859}, {7921, 1}, {7922, 16986115}, + {7923, 1}, {7924, 16986371}, {7925, 1}, {7926, 16986627}, + {7927, 1}, {7928, 16986883}, {7929, 1}, {7930, 16987139}, + {7931, 1}, {7932, 16987395}, {7933, 1}, {7934, 16987651}, + {7935, 1}, {7944, 16987907}, {7945, 16988163}, {7946, 16988419}, + {7947, 16988675}, {7948, 16988931}, {7949, 16989187}, {7950, 16989443}, + {7951, 16989699}, {7952, 1}, {7958, 2}, {7960, 16989955}, + {7961, 16990211}, {7962, 16990467}, {7963, 16990723}, {7964, 16990979}, + {7965, 16991235}, {7966, 2}, {7968, 1}, {7976, 16991491}, + {7977, 16991747}, {7978, 16992003}, {7979, 16992259}, {7980, 16992515}, + {7981, 16992771}, {7982, 16993027}, {7983, 16993283}, {7984, 1}, + {7992, 16993539}, {7993, 16993795}, {7994, 16994051}, {7995, 16994307}, + {7996, 16994563}, {7997, 16994819}, {7998, 16995075}, {7999, 16995331}, + {8000, 1}, {8006, 2}, {8008, 16995587}, {8009, 16995843}, + {8010, 16996099}, {8011, 16996355}, {8012, 16996611}, {8013, 16996867}, + {8014, 2}, {8016, 1}, {8024, 2}, {8025, 16997123}, + {8026, 2}, {8027, 16997379}, {8028, 2}, {8029, 16997635}, + {8030, 2}, {8031, 16997891}, {8032, 1}, {8040, 16998147}, + {8041, 16998403}, {8042, 16998659}, {8043, 16998915}, {8044, 16999171}, + {8045, 16999427}, {8046, 16999683}, {8047, 16999939}, {8048, 1}, + {8049, 16849923}, {8050, 1}, {8051, 16850179}, {8052, 1}, + {8053, 16850435}, {8054, 1}, {8055, 16850691}, {8056, 1}, + {8057, 16850947}, {8058, 1}, {8059, 16851203}, {8060, 1}, + {8061, 16851459}, {8062, 2}, {8064, 33777411}, {8065, 33777923}, + {8066, 33778435}, {8067, 33778947}, {8068, 33779459}, {8069, 33779971}, + {8070, 33780483}, {8071, 33780995}, {8072, 33777411}, {8073, 33777923}, + {8074, 33778435}, {8075, 33778947}, {8076, 33779459}, {8077, 33779971}, + {8078, 33780483}, {8079, 33780995}, {8080, 33781507}, {8081, 33782019}, + {8082, 33782531}, {8083, 33783043}, {8084, 33783555}, {8085, 33784067}, + {8086, 33784579}, {8087, 33785091}, {8088, 33781507}, {8089, 33782019}, + {8090, 33782531}, {8091, 33783043}, {8092, 33783555}, {8093, 33784067}, + {8094, 33784579}, {8095, 33785091}, {8096, 33785603}, {8097, 33786115}, + {8098, 33786627}, {8099, 33787139}, {8100, 33787651}, {8101, 33788163}, + {8102, 33788675}, {8103, 33789187}, {8104, 33785603}, {8105, 33786115}, + {8106, 33786627}, {8107, 33787139}, {8108, 33787651}, {8109, 33788163}, + {8110, 33788675}, {8111, 33789187}, {8112, 1}, {8114, 33789699}, + {8115, 33790211}, {8116, 33790723}, {8117, 2}, {8118, 1}, + {8119, 33791235}, {8120, 17014531}, {8121, 17014787}, {8122, 17012483}, + {8123, 16849923}, {8124, 33790211}, {8125, 33792259}, {8126, 16846851}, + {8127, 33792259}, {8128, 33792771}, {8129, 50570499}, {8130, 33794051}, + {8131, 33794563}, {8132, 33795075}, {8133, 2}, {8134, 1}, + {8135, 33795587}, {8136, 17018883}, {8137, 16850179}, {8138, 17016835}, + {8139, 16850435}, {8140, 33794563}, {8141, 50573571}, {8142, 50574339}, + {8143, 50575107}, {8144, 1}, {8147, 17021443}, {8148, 2}, + {8150, 1}, {8152, 17021699}, {8153, 17021955}, {8154, 17022211}, + {8155, 16850691}, {8156, 2}, {8157, 50576899}, {8158, 50577667}, + {8159, 50578435}, {8160, 1}, {8163, 17024771}, {8164, 1}, + {8168, 17025027}, {8169, 17025283}, {8170, 17025539}, {8171, 16851203}, + {8172, 17025795}, {8173, 50580483}, {8174, 50403587}, {8175, 17026819}, + {8176, 2}, {8178, 33804291}, {8179, 33804803}, {8180, 33805315}, + {8181, 2}, {8182, 1}, {8183, 33805827}, {8184, 17029123}, + {8185, 16850947}, {8186, 17027075}, {8187, 16851459}, {8188, 33804803}, + {8189, 33562883}, {8190, 33799683}, {8191, 2}, {8192, 16783875}, + {8203, 0}, {8204, 1}, {8206, 2}, {8208, 1}, + {8209, 17029379}, {8210, 1}, {8215, 33806851}, {8216, 1}, + {8228, 2}, {8231, 1}, {8232, 2}, {8239, 16783875}, + {8240, 1}, {8243, 33807363}, {8244, 50585091}, {8245, 1}, + {8246, 33808643}, {8247, 50586371}, {8248, 1}, {8252, 33809923}, + {8253, 1}, {8254, 33810435}, {8255, 1}, {8263, 33810947}, + {8264, 33811459}, {8265, 33811971}, {8266, 1}, {8279, 67361795}, + {8280, 1}, {8287, 16783875}, {8288, 0}, {8289, 2}, + {8292, 0}, {8293, 2}, {8304, 17035267}, {8305, 16779267}, + {8306, 2}, {8308, 16787715}, {8309, 17035523}, {8310, 17035779}, + {8311, 17036035}, {8312, 17036291}, {8313, 17036547}, {8314, 17036803}, + {8315, 17037059}, {8316, 17037315}, {8317, 17037571}, {8318, 17037827}, + {8319, 16780547}, {8320, 17035267}, {8321, 16786947}, {8322, 16785155}, + {8323, 16785411}, {8324, 16787715}, {8325, 17035523}, {8326, 17035779}, + {8327, 17036035}, {8328, 17036291}, {8329, 17036547}, {8330, 17036803}, + {8331, 17037059}, {8332, 17037315}, {8333, 17037571}, {8334, 17037827}, + {8335, 2}, {8336, 16777219}, {8337, 16778243}, {8338, 16780803}, + {8339, 16783107}, {8340, 16816387}, {8341, 16779011}, {8342, 16779779}, + {8343, 16780035}, {8344, 16780291}, {8345, 16780547}, {8346, 16781059}, + {8347, 16781827}, {8348, 16782083}, {8349, 2}, {8352, 1}, + {8360, 33558787}, {8361, 1}, {8385, 2}, {8400, 1}, + {8433, 2}, {8448, 50592515}, {8449, 50593283}, {8450, 16777731}, + {8451, 33816835}, {8452, 1}, {8453, 50594563}, {8454, 50595331}, + {8455, 16816643}, {8456, 1}, {8457, 33818883}, {8458, 16778755}, + {8459, 16779011}, {8463, 16802051}, {8464, 16779267}, {8466, 16780035}, + {8468, 1}, {8469, 16780547}, {8470, 33557763}, {8471, 1}, + {8473, 16781059}, {8474, 16781315}, {8475, 16781571}, {8478, 1}, + {8480, 33819395}, {8481, 50597123}, {8482, 33820675}, {8483, 1}, + {8484, 16783619}, {8485, 1}, {8486, 16857091}, {8487, 1}, + {8488, 16783619}, {8489, 1}, {8490, 16779779}, {8491, 16790787}, + {8492, 16777475}, {8493, 16777731}, {8494, 1}, {8495, 16778243}, + {8497, 16778499}, {8498, 2}, {8499, 16780291}, {8500, 16780803}, + {8501, 17043971}, {8502, 17044227}, {8503, 17044483}, {8504, 17044739}, + {8505, 16779267}, {8506, 1}, {8507, 50599427}, {8508, 16855043}, + {8509, 16852227}, {8511, 16855043}, {8512, 17045763}, {8513, 1}, + {8517, 16777987}, {8519, 16778243}, {8520, 16779267}, {8521, 16779523}, + {8522, 1}, {8528, 50600451}, {8529, 50601219}, {8530, 67379203}, + {8531, 50603011}, {8532, 50603779}, {8533, 50604547}, {8534, 50605315}, + {8535, 50606083}, {8536, 50606851}, {8537, 50607619}, {8538, 50608387}, + {8539, 50609155}, {8540, 50609923}, {8541, 50610691}, {8542, 50611459}, + {8543, 33564419}, {8544, 16779267}, {8545, 33835011}, {8546, 50612739}, + {8547, 33836291}, {8548, 16782595}, {8549, 33836803}, {8550, 50614531}, + {8551, 67392515}, {8552, 33839107}, {8553, 16783107}, {8554, 33839619}, + {8555, 50617347}, {8556, 16780035}, {8557, 16777731}, {8558, 16777987}, + {8559, 16780291}, {8560, 16779267}, {8561, 33835011}, {8562, 50612227}, + {8563, 33836291}, {8564, 16782595}, {8565, 33836803}, {8566, 50614531}, + {8567, 67392515}, {8568, 33839107}, {8569, 16783107}, {8570, 33839619}, + {8571, 50617347}, {8572, 16780035}, {8573, 16777731}, {8574, 16777987}, + {8575, 16780291}, {8576, 1}, {8579, 2}, {8580, 1}, + {8585, 50618115}, {8586, 1}, {8588, 2}, {8592, 1}, + {8748, 33841667}, {8749, 50619395}, {8750, 1}, {8751, 33842947}, + {8752, 50620675}, {8753, 1}, {9001, 17067011}, {9002, 17067267}, + {9003, 1}, {9255, 2}, {9280, 1}, {9291, 2}, + {9312, 16786947}, {9313, 16785155}, {9314, 16785411}, {9315, 16787715}, + {9316, 17035523}, {9317, 17035779}, {9318, 17036035}, {9319, 17036291}, + {9320, 17036547}, {9321, 33825283}, {9322, 33564163}, {9323, 33844739}, + {9324, 33845251}, {9325, 33845763}, {9326, 33846275}, {9327, 33846787}, + {9328, 33847299}, {9329, 33847811}, {9330, 33848323}, {9331, 33848835}, + {9332, 50626563}, {9333, 50627331}, {9334, 50628099}, {9335, 50628867}, + {9336, 50629635}, {9337, 50630403}, {9338, 50631171}, {9339, 50631939}, + {9340, 50632707}, {9341, 67410691}, {9342, 67411715}, {9343, 67412739}, + {9344, 67413763}, {9345, 67414787}, {9346, 67415811}, {9347, 67416835}, + {9348, 67417859}, {9349, 67418883}, {9350, 67419907}, {9351, 67420931}, + {9352, 2}, {9372, 50644739}, {9373, 50645507}, {9374, 50646275}, + {9375, 50647043}, {9376, 50647811}, {9377, 50648579}, {9378, 50649347}, + {9379, 50650115}, {9380, 50650883}, {9381, 50651651}, {9382, 50652419}, + {9383, 50653187}, {9384, 50653955}, {9385, 50654723}, {9386, 50655491}, + {9387, 50656259}, {9388, 50657027}, {9389, 50657795}, {9390, 50658563}, + {9391, 50659331}, {9392, 50660099}, {9393, 50660867}, {9394, 50661635}, + {9395, 50662403}, {9396, 50663171}, {9397, 50663939}, {9398, 16777219}, + {9399, 16777475}, {9400, 16777731}, {9401, 16777987}, {9402, 16778243}, + {9403, 16778499}, {9404, 16778755}, {9405, 16779011}, {9406, 16779267}, + {9407, 16779523}, {9408, 16779779}, {9409, 16780035}, {9410, 16780291}, + {9411, 16780547}, {9412, 16780803}, {9413, 16781059}, {9414, 16781315}, + {9415, 16781571}, {9416, 16781827}, {9417, 16782083}, {9418, 16782339}, + {9419, 16782595}, {9420, 16782851}, {9421, 16783107}, {9422, 16783363}, + {9423, 16783619}, {9424, 16777219}, {9425, 16777475}, {9426, 16777731}, + {9427, 16777987}, {9428, 16778243}, {9429, 16778499}, {9430, 16778755}, + {9431, 16779011}, {9432, 16779267}, {9433, 16779523}, {9434, 16779779}, + {9435, 16780035}, {9436, 16780291}, {9437, 16780547}, {9438, 16780803}, + {9439, 16781059}, {9440, 16781315}, {9441, 16781571}, {9442, 16781827}, + {9443, 16782083}, {9444, 16782339}, {9445, 16782595}, {9446, 16782851}, + {9447, 16783107}, {9448, 16783363}, {9449, 16783619}, {9450, 17035267}, + {9451, 1}, {10764, 67396099}, {10765, 1}, {10868, 50664707}, + {10869, 33888259}, {10870, 50665219}, {10871, 1}, {10972, 33888771}, + {10973, 1}, {11124, 2}, {11126, 1}, {11158, 2}, + {11159, 1}, {11264, 17112067}, {11265, 17112323}, {11266, 17112579}, + {11267, 17112835}, {11268, 17113091}, {11269, 17113347}, {11270, 17113603}, + {11271, 17113859}, {11272, 17114115}, {11273, 17114371}, {11274, 17114627}, + {11275, 17114883}, {11276, 17115139}, {11277, 17115395}, {11278, 17115651}, + {11279, 17115907}, {11280, 17116163}, {11281, 17116419}, {11282, 17116675}, + {11283, 17116931}, {11284, 17117187}, {11285, 17117443}, {11286, 17117699}, + {11287, 17117955}, {11288, 17118211}, {11289, 17118467}, {11290, 17118723}, + {11291, 17118979}, {11292, 17119235}, {11293, 17119491}, {11294, 17119747}, + {11295, 17120003}, {11296, 17120259}, {11297, 17120515}, {11298, 17120771}, + {11299, 17121027}, {11300, 17121283}, {11301, 17121539}, {11302, 17121795}, + {11303, 17122051}, {11304, 17122307}, {11305, 17122563}, {11306, 17122819}, + {11307, 17123075}, {11308, 17123331}, {11309, 17123587}, {11310, 17123843}, + {11311, 17124099}, {11312, 1}, {11360, 17124355}, {11361, 1}, + {11362, 17124611}, {11363, 17124867}, {11364, 17125123}, {11365, 1}, + {11367, 17125379}, {11368, 1}, {11369, 17125635}, {11370, 1}, + {11371, 17125891}, {11372, 1}, {11373, 16948483}, {11374, 16953091}, + {11375, 16948227}, {11376, 16950275}, {11377, 1}, {11378, 17126147}, + {11379, 1}, {11381, 17126403}, {11382, 1}, {11388, 16779523}, + {11389, 16782595}, {11390, 17126659}, {11391, 17126915}, {11392, 17127171}, + {11393, 1}, {11394, 17127427}, {11395, 1}, {11396, 17127683}, + {11397, 1}, {11398, 17127939}, {11399, 1}, {11400, 17128195}, + {11401, 1}, {11402, 17128451}, {11403, 1}, {11404, 17128707}, + {11405, 1}, {11406, 17128963}, {11407, 1}, {11408, 17129219}, + {11409, 1}, {11410, 17129475}, {11411, 1}, {11412, 17129731}, + {11413, 1}, {11414, 17129987}, {11415, 1}, {11416, 17130243}, + {11417, 1}, {11418, 17130499}, {11419, 1}, {11420, 17130755}, + {11421, 1}, {11422, 17131011}, {11423, 1}, {11424, 17131267}, + {11425, 1}, {11426, 17131523}, {11427, 1}, {11428, 17131779}, + {11429, 1}, {11430, 17132035}, {11431, 1}, {11432, 17132291}, + {11433, 1}, {11434, 17132547}, {11435, 1}, {11436, 17132803}, + {11437, 1}, {11438, 17133059}, {11439, 1}, {11440, 17133315}, + {11441, 1}, {11442, 17133571}, {11443, 1}, {11444, 17133827}, + {11445, 1}, {11446, 17134083}, {11447, 1}, {11448, 17134339}, + {11449, 1}, {11450, 17134595}, {11451, 1}, {11452, 17134851}, + {11453, 1}, {11454, 17135107}, {11455, 1}, {11456, 17135363}, + {11457, 1}, {11458, 17135619}, {11459, 1}, {11460, 17135875}, + {11461, 1}, {11462, 17136131}, {11463, 1}, {11464, 17136387}, + {11465, 1}, {11466, 17136643}, {11467, 1}, {11468, 17136899}, + {11469, 1}, {11470, 17137155}, {11471, 1}, {11472, 17137411}, + {11473, 1}, {11474, 17137667}, {11475, 1}, {11476, 17137923}, + {11477, 1}, {11478, 17138179}, {11479, 1}, {11480, 17138435}, + {11481, 1}, {11482, 17138691}, {11483, 1}, {11484, 17138947}, + {11485, 1}, {11486, 17139203}, {11487, 1}, {11488, 17139459}, + {11489, 1}, {11490, 17139715}, {11491, 1}, {11499, 17139971}, + {11500, 1}, {11501, 17140227}, {11502, 1}, {11506, 17140483}, + {11507, 1}, {11508, 2}, {11513, 1}, {11558, 2}, + {11559, 1}, {11560, 2}, {11565, 1}, {11566, 2}, + {11568, 1}, {11624, 2}, {11631, 17140739}, {11632, 1}, + {11633, 2}, {11647, 1}, {11671, 2}, {11680, 1}, + {11687, 2}, {11688, 1}, {11695, 2}, {11696, 1}, + {11703, 2}, {11704, 1}, {11711, 2}, {11712, 1}, + {11719, 2}, {11720, 1}, {11727, 2}, {11728, 1}, + {11735, 2}, {11736, 1}, {11743, 2}, {11744, 1}, + {11870, 2}, {11904, 1}, {11930, 2}, {11931, 1}, + {11935, 17140995}, {11936, 1}, {12019, 17141251}, {12020, 2}, + {12032, 17141507}, {12033, 17141763}, {12034, 17142019}, {12035, 17142275}, + {12036, 17142531}, {12037, 17142787}, {12038, 17143043}, {12039, 17143299}, + {12040, 17143555}, {12041, 17143811}, {12042, 17144067}, {12043, 17144323}, + {12044, 17144579}, {12045, 17144835}, {12046, 17145091}, {12047, 17145347}, + {12048, 17145603}, {12049, 17145859}, {12050, 17146115}, {12051, 17146371}, + {12052, 17146627}, {12053, 17146883}, {12054, 17147139}, {12055, 17147395}, + {12056, 17147651}, {12057, 17147907}, {12058, 17148163}, {12059, 17148419}, + {12060, 17148675}, {12061, 17148931}, {12062, 17149187}, {12063, 17149443}, + {12064, 17149699}, {12065, 17149955}, {12066, 17150211}, {12067, 17150467}, + {12068, 17150723}, {12069, 17150979}, {12070, 17151235}, {12071, 17151491}, + {12072, 17151747}, {12073, 17152003}, {12074, 17152259}, {12075, 17152515}, + {12076, 17152771}, {12077, 17153027}, {12078, 17153283}, {12079, 17153539}, + {12080, 17153795}, {12081, 17154051}, {12082, 17154307}, {12083, 17154563}, + {12084, 17154819}, {12085, 17155075}, {12086, 17155331}, {12087, 17155587}, + {12088, 17155843}, {12089, 17156099}, {12090, 17156355}, {12091, 17156611}, + {12092, 17156867}, {12093, 17157123}, {12094, 17157379}, {12095, 17157635}, + {12096, 17157891}, {12097, 17158147}, {12098, 17158403}, {12099, 17158659}, + {12100, 17158915}, {12101, 17159171}, {12102, 17159427}, {12103, 17159683}, + {12104, 17159939}, {12105, 17160195}, {12106, 17160451}, {12107, 17160707}, + {12108, 17160963}, {12109, 17161219}, {12110, 17161475}, {12111, 17161731}, + {12112, 17161987}, {12113, 17162243}, {12114, 17162499}, {12115, 17162755}, + {12116, 17163011}, {12117, 17163267}, {12118, 17163523}, {12119, 17163779}, + {12120, 17164035}, {12121, 17164291}, {12122, 17164547}, {12123, 17164803}, + {12124, 17165059}, {12125, 17165315}, {12126, 17165571}, {12127, 17165827}, + {12128, 17166083}, {12129, 17166339}, {12130, 17166595}, {12131, 17166851}, + {12132, 17167107}, {12133, 17167363}, {12134, 17167619}, {12135, 17167875}, + {12136, 17168131}, {12137, 17168387}, {12138, 17168643}, {12139, 17168899}, + {12140, 17169155}, {12141, 17169411}, {12142, 17169667}, {12143, 17169923}, + {12144, 17170179}, {12145, 17170435}, {12146, 17170691}, {12147, 17170947}, + {12148, 17171203}, {12149, 17171459}, {12150, 17171715}, {12151, 17171971}, + {12152, 17172227}, {12153, 17172483}, {12154, 17172739}, {12155, 17172995}, + {12156, 17173251}, {12157, 17173507}, {12158, 17173763}, {12159, 17174019}, + {12160, 17174275}, {12161, 17174531}, {12162, 17174787}, {12163, 17175043}, + {12164, 17175299}, {12165, 17175555}, {12166, 17175811}, {12167, 17176067}, + {12168, 17176323}, {12169, 17176579}, {12170, 17176835}, {12171, 17177091}, + {12172, 17177347}, {12173, 17177603}, {12174, 17177859}, {12175, 17178115}, + {12176, 17178371}, {12177, 17178627}, {12178, 17178883}, {12179, 17179139}, + {12180, 17179395}, {12181, 17179651}, {12182, 17179907}, {12183, 17180163}, + {12184, 17180419}, {12185, 17180675}, {12186, 17180931}, {12187, 17181187}, + {12188, 17181443}, {12189, 17181699}, {12190, 17181955}, {12191, 17182211}, + {12192, 17182467}, {12193, 17182723}, {12194, 17182979}, {12195, 17183235}, + {12196, 17183491}, {12197, 17183747}, {12198, 17184003}, {12199, 17184259}, + {12200, 17184515}, {12201, 17184771}, {12202, 17185027}, {12203, 17185283}, + {12204, 17185539}, {12205, 17185795}, {12206, 17186051}, {12207, 17186307}, + {12208, 17186563}, {12209, 17186819}, {12210, 17187075}, {12211, 17187331}, + {12212, 17187587}, {12213, 17187843}, {12214, 17188099}, {12215, 17188355}, + {12216, 17188611}, {12217, 17188867}, {12218, 17189123}, {12219, 17189379}, + {12220, 17189635}, {12221, 17189891}, {12222, 17190147}, {12223, 17190403}, + {12224, 17190659}, {12225, 17190915}, {12226, 17191171}, {12227, 17191427}, + {12228, 17191683}, {12229, 17191939}, {12230, 17192195}, {12231, 17192451}, + {12232, 17192707}, {12233, 17192963}, {12234, 17193219}, {12235, 17193475}, + {12236, 17193731}, {12237, 17193987}, {12238, 17194243}, {12239, 17194499}, + {12240, 17194755}, {12241, 17195011}, {12242, 17195267}, {12243, 17195523}, + {12244, 17195779}, {12245, 17196035}, {12246, 2}, {12288, 16783875}, + {12289, 1}, {12290, 17196291}, {12291, 1}, {12342, 17196547}, + {12343, 1}, {12344, 17147395}, {12345, 17196803}, {12346, 17197059}, + {12347, 1}, {12352, 2}, {12353, 1}, {12439, 2}, + {12441, 1}, {12443, 33974531}, {12444, 33975043}, {12445, 1}, + {12447, 33975555}, {12448, 1}, {12543, 33976067}, {12544, 2}, + {12549, 1}, {12592, 2}, {12593, 17199363}, {12594, 17199619}, + {12595, 17199875}, {12596, 17200131}, {12597, 17200387}, {12598, 17200643}, + {12599, 17200899}, {12600, 17201155}, {12601, 17201411}, {12602, 17201667}, + {12603, 17201923}, {12604, 17202179}, {12605, 17202435}, {12606, 17202691}, + {12607, 17202947}, {12608, 17203203}, {12609, 17203459}, {12610, 17203715}, + {12611, 17203971}, {12612, 17204227}, {12613, 17204483}, {12614, 17204739}, + {12615, 17204995}, {12616, 17205251}, {12617, 17205507}, {12618, 17205763}, + {12619, 17206019}, {12620, 17206275}, {12621, 17206531}, {12622, 17206787}, + {12623, 17207043}, {12624, 17207299}, {12625, 17207555}, {12626, 17207811}, + {12627, 17208067}, {12628, 17208323}, {12629, 17208579}, {12630, 17208835}, + {12631, 17209091}, {12632, 17209347}, {12633, 17209603}, {12634, 17209859}, + {12635, 17210115}, {12636, 17210371}, {12637, 17210627}, {12638, 17210883}, + {12639, 17211139}, {12640, 17211395}, {12641, 17211651}, {12642, 17211907}, + {12643, 17212163}, {12644, 2}, {12645, 17212419}, {12646, 17212675}, + {12647, 17212931}, {12648, 17213187}, {12649, 17213443}, {12650, 17213699}, + {12651, 17213955}, {12652, 17214211}, {12653, 17214467}, {12654, 17214723}, + {12655, 17214979}, {12656, 17215235}, {12657, 17215491}, {12658, 17215747}, + {12659, 17216003}, {12660, 17216259}, {12661, 17216515}, {12662, 17216771}, + {12663, 17217027}, {12664, 17217283}, {12665, 17217539}, {12666, 17217795}, + {12667, 17218051}, {12668, 17218307}, {12669, 17218563}, {12670, 17218819}, + {12671, 17219075}, {12672, 17219331}, {12673, 17219587}, {12674, 17219843}, + {12675, 17220099}, {12676, 17220355}, {12677, 17220611}, {12678, 17220867}, + {12679, 17221123}, {12680, 17221379}, {12681, 17221635}, {12682, 17221891}, + {12683, 17222147}, {12684, 17222403}, {12685, 17222659}, {12686, 17222915}, + {12687, 2}, {12688, 1}, {12690, 17141507}, {12691, 17143043}, + {12692, 17223171}, {12693, 17223427}, {12694, 17223683}, {12695, 17223939}, + {12696, 17224195}, {12697, 17224451}, {12698, 17142531}, {12699, 17224707}, + {12700, 17224963}, {12701, 17225219}, {12702, 17225475}, {12703, 17143555}, + {12704, 1}, {12772, 2}, {12784, 1}, {12800, 50780163}, + {12801, 50780931}, {12802, 50781699}, {12803, 50782467}, {12804, 50783235}, + {12805, 50784003}, {12806, 50784771}, {12807, 50785539}, {12808, 50786307}, + {12809, 50787075}, {12810, 50787843}, {12811, 50788611}, {12812, 50789379}, + {12813, 50790147}, {12814, 50790915}, {12815, 50791683}, {12816, 50792451}, + {12817, 50793219}, {12818, 50793987}, {12819, 50794755}, {12820, 50795523}, + {12821, 50796291}, {12822, 50797059}, {12823, 50797827}, {12824, 50798595}, + {12825, 50799363}, {12826, 50800131}, {12827, 50800899}, {12828, 50801667}, + {12829, 67579651}, {12830, 67580675}, {12831, 2}, {12832, 50804483}, + {12833, 50805251}, {12834, 50806019}, {12835, 50806787}, {12836, 50807555}, + {12837, 50808323}, {12838, 50809091}, {12839, 50809859}, {12840, 50810627}, + {12841, 50811395}, {12842, 50812163}, {12843, 50812931}, {12844, 50813699}, + {12845, 50814467}, {12846, 50815235}, {12847, 50816003}, {12848, 50816771}, + {12849, 50817539}, {12850, 50818307}, {12851, 50819075}, {12852, 50819843}, + {12853, 50820611}, {12854, 50821379}, {12855, 50822147}, {12856, 50822915}, + {12857, 50823683}, {12858, 50824451}, {12859, 50825219}, {12860, 50825987}, + {12861, 50826755}, {12862, 50827523}, {12863, 50828291}, {12864, 50829059}, + {12865, 50829827}, {12866, 50830595}, {12867, 50831363}, {12868, 17277699}, + {12869, 17277955}, {12870, 17158403}, {12871, 17278211}, {12872, 1}, + {12880, 50832899}, {12881, 33844995}, {12882, 34056451}, {12883, 33562371}, + {12884, 34056963}, {12885, 34057475}, {12886, 34057987}, {12887, 34058499}, + {12888, 34059011}, {12889, 34059523}, {12890, 34060035}, {12891, 33827075}, + {12892, 33826307}, {12893, 34060547}, {12894, 34061059}, {12895, 34061571}, + {12896, 17199363}, {12897, 17200131}, {12898, 17200899}, {12899, 17201411}, + {12900, 17203459}, {12901, 17203715}, {12902, 17204483}, {12903, 17204995}, + {12904, 17205251}, {12905, 17205763}, {12906, 17206019}, {12907, 17206275}, + {12908, 17206531}, {12909, 17206787}, {12910, 17236739}, {12911, 17237507}, + {12912, 17238275}, {12913, 17239043}, {12914, 17239811}, {12915, 17240579}, + {12916, 17241347}, {12917, 17242115}, {12918, 17242883}, {12919, 17243651}, + {12920, 17244419}, {12921, 17245187}, {12922, 17245955}, {12923, 17246723}, + {12924, 34062083}, {12925, 34062595}, {12926, 17285891}, {12927, 1}, + {12928, 17141507}, {12929, 17143043}, {12930, 17223171}, {12931, 17223427}, + {12932, 17253379}, {12933, 17254147}, {12934, 17254915}, {12935, 17144323}, + {12936, 17256451}, {12937, 17147395}, {12938, 17160195}, {12939, 17163267}, + {12940, 17163011}, {12941, 17160451}, {12942, 17184003}, {12943, 17149443}, + {12944, 17159683}, {12945, 17263363}, {12946, 17264131}, {12947, 17264899}, + {12948, 17265667}, {12949, 17266435}, {12950, 17267203}, {12951, 17267971}, + {12952, 17268739}, {12953, 17286147}, {12954, 17286403}, {12955, 17150979}, + {12956, 17286659}, {12957, 17286915}, {12958, 17287171}, {12959, 17287427}, + {12960, 17287683}, {12961, 17275651}, {12962, 17287939}, {12963, 17288195}, + {12964, 17223683}, {12965, 17223939}, {12966, 17224195}, {12967, 17288451}, + {12968, 17288707}, {12969, 17288963}, {12970, 17289219}, {12971, 17271043}, + {12972, 17271811}, {12973, 17272579}, {12974, 17273347}, {12975, 17274115}, + {12976, 17289475}, {12977, 34066947}, {12978, 34067459}, {12979, 34067971}, + {12980, 34068483}, {12981, 34068995}, {12982, 33564931}, {12983, 34057219}, + {12984, 34061315}, {12985, 34069507}, {12986, 34070019}, {12987, 34070531}, + {12988, 34071043}, {12989, 34071555}, {12990, 34072067}, {12991, 34072579}, + {12992, 34073091}, {12993, 34073603}, {12994, 34074115}, {12995, 34074627}, + {12996, 34075139}, {12997, 34075651}, {12998, 34076163}, {12999, 34076675}, + {13000, 34077187}, {13001, 50854915}, {13002, 50855683}, {13003, 50856451}, + {13004, 34080003}, {13005, 50857731}, {13006, 34081283}, {13007, 50859011}, + {13008, 17305347}, {13009, 17305603}, {13010, 17305859}, {13011, 17306115}, + {13012, 17306371}, {13013, 17306627}, {13014, 17306883}, {13015, 17307139}, + {13016, 17307395}, {13017, 17198851}, {13018, 17307651}, {13019, 17307907}, + {13020, 17308163}, {13021, 17308419}, {13022, 17308675}, {13023, 17308931}, + {13024, 17309187}, {13025, 17309443}, {13026, 17309699}, {13027, 17199107}, + {13028, 17309955}, {13029, 17310211}, {13030, 17310467}, {13031, 17310723}, + {13032, 17310979}, {13033, 17311235}, {13034, 17311491}, {13035, 17311747}, + {13036, 17312003}, {13037, 17312259}, {13038, 17312515}, {13039, 17312771}, + {13040, 17313027}, {13041, 17313283}, {13042, 17313539}, {13043, 17313795}, + {13044, 17314051}, {13045, 17314307}, {13046, 17314563}, {13047, 17314819}, + {13048, 17315075}, {13049, 17315331}, {13050, 17315587}, {13051, 17315843}, + {13052, 17316099}, {13053, 17316355}, {13054, 17316611}, {13055, 34094083}, + {13056, 67649027}, {13057, 67650051}, {13058, 67651075}, {13059, 50874883}, + {13060, 67652867}, {13061, 50876675}, {13062, 50877443}, {13063, 84432643}, + {13064, 67656707}, {13065, 50880515}, {13066, 50881283}, {13067, 50882051}, + {13068, 67660035}, {13069, 67661059}, {13070, 50884867}, {13071, 50885635}, + {13072, 34109187}, {13073, 50886915}, {13074, 67664899}, {13075, 67665923}, + {13076, 34112515}, {13077, 84444675}, {13078, 101223171}, {13079, 84447491}, + {13080, 50890755}, {13081, 84448771}, {13082, 84450051}, {13083, 67674115}, + {13084, 50897923}, {13085, 50898691}, {13086, 50899459}, {13087, 67677443}, + {13088, 84455683}, {13089, 67679747}, {13090, 50903555}, {13091, 50904323}, + {13092, 50905091}, {13093, 34128643}, {13094, 34129155}, {13095, 34117891}, + {13096, 34129667}, {13097, 50907395}, {13098, 50908163}, {13099, 84463363}, + {13100, 50910211}, {13101, 67688195}, {13102, 84466435}, {13103, 50913283}, + {13104, 34136835}, {13105, 34137347}, {13106, 84469507}, {13107, 67693571}, + {13108, 84471811}, {13109, 50918659}, {13110, 84473859}, {13111, 34143491}, + {13112, 50921219}, {13113, 50921987}, {13114, 50922755}, {13115, 50923523}, + {13116, 50924291}, {13117, 67702275}, {13118, 50926083}, {13119, 34149635}, + {13120, 50927363}, {13121, 50928131}, {13122, 50928899}, {13123, 67706883}, + {13124, 50930691}, {13125, 50931459}, {13126, 50932227}, {13127, 84487427}, + {13128, 67711491}, {13129, 34158083}, {13130, 84490243}, {13131, 34159875}, + {13132, 67714819}, {13133, 67669251}, {13134, 50938627}, {13135, 50939395}, + {13136, 50940163}, {13137, 67718147}, {13138, 34164739}, {13139, 50942467}, + {13140, 67720451}, {13141, 34167043}, {13142, 84499203}, {13143, 50893571}, + {13144, 34168835}, {13145, 34169347}, {13146, 34169859}, {13147, 34170371}, + {13148, 34170883}, {13149, 34171395}, {13150, 34171907}, {13151, 34172419}, + {13152, 34172931}, {13153, 34173443}, {13154, 50951171}, {13155, 50951939}, + {13156, 50952707}, {13157, 50953475}, {13158, 50954243}, {13159, 50955011}, + {13160, 50955779}, {13161, 50956547}, {13162, 50957315}, {13163, 50958083}, + {13164, 50958851}, {13165, 50959619}, {13166, 50960387}, {13167, 50961155}, + {13168, 50961923}, {13169, 50962691}, {13170, 34186243}, {13171, 34186755}, + {13172, 50964483}, {13173, 34188035}, {13174, 34188547}, {13175, 34189059}, + {13176, 50966787}, {13177, 50967555}, {13178, 34191107}, {13179, 34191619}, + {13180, 34192131}, {13181, 34192643}, {13182, 34193155}, {13183, 67748099}, + {13184, 34185731}, {13185, 34194691}, {13186, 34195203}, {13187, 34195715}, + {13188, 34196227}, {13189, 34196739}, {13190, 34197251}, {13191, 34197763}, + {13192, 50975491}, {13193, 67753475}, {13194, 34200067}, {13195, 34200579}, + {13196, 34201091}, {13197, 34201603}, {13198, 34202115}, {13199, 34202627}, + {13200, 34203139}, {13201, 50980867}, {13202, 50981635}, {13203, 50980099}, + {13204, 50982403}, {13205, 34205955}, {13206, 34206467}, {13207, 34206979}, + {13208, 33556995}, {13209, 34207491}, {13210, 34208003}, {13211, 34208515}, + {13212, 34209027}, {13213, 34209539}, {13214, 34210051}, {13215, 50987779}, + {13216, 50988547}, {13217, 34189827}, {13218, 50989315}, {13219, 50990083}, + {13220, 50990851}, {13221, 34190595}, {13222, 50991619}, {13223, 50992387}, + {13224, 67770371}, {13225, 34185731}, {13226, 50994179}, {13227, 50994947}, + {13228, 50995715}, {13229, 50996483}, {13230, 84551683}, {13231, 101330179}, + {13232, 34222851}, {13233, 34223363}, {13234, 34223875}, {13235, 34224387}, + {13236, 34224899}, {13237, 34225411}, {13238, 34225923}, {13239, 34226435}, + {13240, 34226947}, {13241, 34226435}, {13242, 34227459}, {13243, 34227971}, + {13244, 34228483}, {13245, 34228995}, {13246, 34229507}, {13247, 34228995}, + {13248, 34230019}, {13249, 34230531}, {13250, 2}, {13251, 34231043}, + {13252, 33817091}, {13253, 33554947}, {13254, 67785987}, {13255, 2}, + {13256, 34232579}, {13257, 34233091}, {13258, 34233603}, {13259, 34185475}, + {13260, 34234115}, {13261, 34234627}, {13262, 34210051}, {13263, 34235139}, + {13264, 33557251}, {13265, 34235651}, {13266, 51013379}, {13267, 34236931}, + {13268, 34197251}, {13269, 51014659}, {13270, 51015427}, {13271, 34238979}, + {13272, 2}, {13273, 51016707}, {13274, 34240259}, {13275, 34221059}, + {13276, 34240771}, {13277, 34241283}, {13278, 51019011}, {13279, 51019779}, + {13280, 34243331}, {13281, 34243843}, {13282, 34244355}, {13283, 34244867}, + {13284, 34245379}, {13285, 34245891}, {13286, 34246403}, {13287, 34246915}, + {13288, 34247427}, {13289, 51025155}, {13290, 51025923}, {13291, 51026691}, + {13292, 51027459}, {13293, 51028227}, {13294, 51028995}, {13295, 51029763}, + {13296, 51030531}, {13297, 51031299}, {13298, 51032067}, {13299, 51032835}, + {13300, 51033603}, {13301, 51034371}, {13302, 51035139}, {13303, 51035907}, + {13304, 51036675}, {13305, 51037443}, {13306, 51038211}, {13307, 51038979}, + {13308, 51039747}, {13309, 51040515}, {13310, 51041283}, {13311, 51042051}, + {13312, 1}, {42125, 2}, {42128, 1}, {42183, 2}, + {42192, 1}, {42540, 2}, {42560, 17488387}, {42561, 1}, + {42562, 17488643}, {42563, 1}, {42564, 17488899}, {42565, 1}, + {42566, 17489155}, {42567, 1}, {42568, 17489411}, {42569, 1}, + {42570, 16936451}, {42571, 1}, {42572, 17489667}, {42573, 1}, + {42574, 17489923}, {42575, 1}, {42576, 17490179}, {42577, 1}, + {42578, 17490435}, {42579, 1}, {42580, 17490691}, {42581, 1}, + {42582, 17490947}, {42583, 1}, {42584, 17491203}, {42585, 1}, + {42586, 17491459}, {42587, 1}, {42588, 17491715}, {42589, 1}, + {42590, 17491971}, {42591, 1}, {42592, 17492227}, {42593, 1}, + {42594, 17492483}, {42595, 1}, {42596, 17492739}, {42597, 1}, + {42598, 17492995}, {42599, 1}, {42600, 17493251}, {42601, 1}, + {42602, 17493507}, {42603, 1}, {42604, 17493763}, {42605, 1}, + {42624, 17494019}, {42625, 1}, {42626, 17494275}, {42627, 1}, + {42628, 17494531}, {42629, 1}, {42630, 17494787}, {42631, 1}, + {42632, 17495043}, {42633, 1}, {42634, 17495299}, {42635, 1}, + {42636, 17495555}, {42637, 1}, {42638, 17495811}, {42639, 1}, + {42640, 17496067}, {42641, 1}, {42642, 17496323}, {42643, 1}, + {42644, 17496579}, {42645, 1}, {42646, 17496835}, {42647, 1}, + {42648, 17497091}, {42649, 1}, {42650, 17497347}, {42651, 1}, + {42652, 16873219}, {42653, 16873731}, {42654, 1}, {42744, 2}, + {42752, 1}, {42786, 17497603}, {42787, 1}, {42788, 17497859}, + {42789, 1}, {42790, 17498115}, {42791, 1}, {42792, 17498371}, + {42793, 1}, {42794, 17498627}, {42795, 1}, {42796, 17498883}, + {42797, 1}, {42798, 17499139}, {42799, 1}, {42802, 17499395}, + {42803, 1}, {42804, 17499651}, {42805, 1}, {42806, 17499907}, + {42807, 1}, {42808, 17500163}, {42809, 1}, {42810, 17500419}, + {42811, 1}, {42812, 17500675}, {42813, 1}, {42814, 17500931}, + {42815, 1}, {42816, 17501187}, {42817, 1}, {42818, 17501443}, + {42819, 1}, {42820, 17501699}, {42821, 1}, {42822, 17501955}, + {42823, 1}, {42824, 17502211}, {42825, 1}, {42826, 17502467}, + {42827, 1}, {42828, 17502723}, {42829, 1}, {42830, 17502979}, + {42831, 1}, {42832, 17503235}, {42833, 1}, {42834, 17503491}, + {42835, 1}, {42836, 17503747}, {42837, 1}, {42838, 17504003}, + {42839, 1}, {42840, 17504259}, {42841, 1}, {42842, 17504515}, + {42843, 1}, {42844, 17504771}, {42845, 1}, {42846, 17505027}, + {42847, 1}, {42848, 17505283}, {42849, 1}, {42850, 17505539}, + {42851, 1}, {42852, 17505795}, {42853, 1}, {42854, 17506051}, + {42855, 1}, {42856, 17506307}, {42857, 1}, {42858, 17506563}, + {42859, 1}, {42860, 17506819}, {42861, 1}, {42862, 17507075}, + {42863, 1}, {42864, 17507075}, {42865, 1}, {42873, 17507331}, + {42874, 1}, {42875, 17507587}, {42876, 1}, {42877, 17507843}, + {42878, 17508099}, {42879, 1}, {42880, 17508355}, {42881, 1}, + {42882, 17508611}, {42883, 1}, {42884, 17508867}, {42885, 1}, + {42886, 17509123}, {42887, 1}, {42891, 17509379}, {42892, 1}, + {42893, 16951299}, {42894, 1}, {42896, 17509635}, {42897, 1}, + {42898, 17509891}, {42899, 1}, {42902, 17510147}, {42903, 1}, + {42904, 17510403}, {42905, 1}, {42906, 17510659}, {42907, 1}, + {42908, 17510915}, {42909, 1}, {42910, 17511171}, {42911, 1}, + {42912, 17511427}, {42913, 1}, {42914, 17511683}, {42915, 1}, + {42916, 17511939}, {42917, 1}, {42918, 17512195}, {42919, 1}, + {42920, 17512451}, {42921, 1}, {42922, 16841475}, {42923, 16948995}, + {42924, 16951043}, {42925, 17512707}, {42926, 16951555}, {42927, 1}, + {42928, 17512963}, {42929, 17513219}, {42930, 16952067}, {42931, 17513475}, + {42932, 17513731}, {42933, 1}, {42934, 17513987}, {42935, 1}, + {42936, 17514243}, {42937, 1}, {42938, 17514499}, {42939, 1}, + {42940, 17514755}, {42941, 1}, {42942, 17515011}, {42943, 1}, + {42944, 17515267}, {42945, 1}, {42946, 17515523}, {42947, 1}, + {42948, 17515779}, {42949, 16954371}, {42950, 17516035}, {42951, 17516291}, + {42952, 1}, {42953, 17516547}, {42954, 1}, {42955, 2}, + {42960, 17516803}, {42961, 1}, {42962, 2}, {42963, 1}, + {42964, 2}, {42965, 1}, {42966, 17517059}, {42967, 1}, + {42968, 17517315}, {42969, 1}, {42970, 2}, {42994, 16777731}, + {42995, 16778499}, {42996, 16781315}, {42997, 17517571}, {42998, 1}, + {43000, 16802051}, {43001, 16808195}, {43002, 1}, {43053, 2}, + {43056, 1}, {43066, 2}, {43072, 1}, {43128, 2}, + {43136, 1}, {43206, 2}, {43214, 1}, {43226, 2}, + {43232, 1}, {43348, 2}, {43359, 1}, {43389, 2}, + {43392, 1}, {43470, 2}, {43471, 1}, {43482, 2}, + {43486, 1}, {43519, 2}, {43520, 1}, {43575, 2}, + {43584, 1}, {43598, 2}, {43600, 1}, {43610, 2}, + {43612, 1}, {43715, 2}, {43739, 1}, {43767, 2}, + {43777, 1}, {43783, 2}, {43785, 1}, {43791, 2}, + {43793, 1}, {43799, 2}, {43808, 1}, {43815, 2}, + {43816, 1}, {43823, 2}, {43824, 1}, {43868, 17498115}, + {43869, 17517827}, {43870, 17124611}, {43871, 17518083}, {43872, 1}, + {43881, 17518339}, {43882, 1}, {43884, 2}, {43888, 17518595}, + {43889, 17518851}, {43890, 17519107}, {43891, 17519363}, {43892, 17519619}, + {43893, 17519875}, {43894, 17520131}, {43895, 17520387}, {43896, 17520643}, + {43897, 17520899}, {43898, 17521155}, {43899, 17521411}, {43900, 17521667}, + {43901, 17521923}, {43902, 17522179}, {43903, 17522435}, {43904, 17522691}, + {43905, 17522947}, {43906, 17523203}, {43907, 17523459}, {43908, 17523715}, + {43909, 17523971}, {43910, 17524227}, {43911, 17524483}, {43912, 17524739}, + {43913, 17524995}, {43914, 17525251}, {43915, 17525507}, {43916, 17525763}, + {43917, 17526019}, {43918, 17526275}, {43919, 17526531}, {43920, 17526787}, + {43921, 17527043}, {43922, 17527299}, {43923, 17527555}, {43924, 17527811}, + {43925, 17528067}, {43926, 17528323}, {43927, 17528579}, {43928, 17528835}, + {43929, 17529091}, {43930, 17529347}, {43931, 17529603}, {43932, 17529859}, + {43933, 17530115}, {43934, 17530371}, {43935, 17530627}, {43936, 17530883}, + {43937, 17531139}, {43938, 17531395}, {43939, 17531651}, {43940, 17531907}, + {43941, 17532163}, {43942, 17532419}, {43943, 17532675}, {43944, 17532931}, + {43945, 17533187}, {43946, 17533443}, {43947, 17533699}, {43948, 17533955}, + {43949, 17534211}, {43950, 17534467}, {43951, 17534723}, {43952, 17534979}, + {43953, 17535235}, {43954, 17535491}, {43955, 17535747}, {43956, 17536003}, + {43957, 17536259}, {43958, 17536515}, {43959, 17536771}, {43960, 17537027}, + {43961, 17537283}, {43962, 17537539}, {43963, 17537795}, {43964, 17538051}, + {43965, 17538307}, {43966, 17538563}, {43967, 17538819}, {43968, 1}, + {44014, 2}, {44016, 1}, {44026, 2}, {44032, 1}, + {55204, 2}, {55216, 1}, {55239, 2}, {55243, 1}, + {55292, 2}, {63744, 17539075}, {63745, 17539331}, {63746, 17181955}, + {63747, 17539587}, {63748, 17539843}, {63749, 17540099}, {63750, 17540355}, + {63751, 17195779}, {63753, 17540611}, {63754, 17184003}, {63755, 17540867}, + {63756, 17541123}, {63757, 17541379}, {63758, 17541635}, {63759, 17541891}, + {63760, 17542147}, {63761, 17542403}, {63762, 17542659}, {63763, 17542915}, + {63764, 17543171}, {63765, 17543427}, {63766, 17543683}, {63767, 17543939}, + {63768, 17544195}, {63769, 17544451}, {63770, 17544707}, {63771, 17544963}, + {63772, 17545219}, {63773, 17545475}, {63774, 17545731}, {63775, 17545987}, + {63776, 17546243}, {63777, 17546499}, {63778, 17546755}, {63779, 17547011}, + {63780, 17547267}, {63781, 17547523}, {63782, 17547779}, {63783, 17548035}, + {63784, 17548291}, {63785, 17548547}, {63786, 17548803}, {63787, 17549059}, + {63788, 17549315}, {63789, 17549571}, {63790, 17549827}, {63791, 17550083}, + {63792, 17550339}, {63793, 17550595}, {63794, 17550851}, {63795, 17551107}, + {63796, 17173251}, {63797, 17551363}, {63798, 17551619}, {63799, 17551875}, + {63800, 17552131}, {63801, 17552387}, {63802, 17552643}, {63803, 17552899}, + {63804, 17553155}, {63805, 17553411}, {63806, 17553667}, {63807, 17553923}, + {63808, 17191939}, {63809, 17554179}, {63810, 17554435}, {63811, 17554691}, + {63812, 17554947}, {63813, 17555203}, {63814, 17555459}, {63815, 17555715}, + {63816, 17555971}, {63817, 17556227}, {63818, 17556483}, {63819, 17556739}, + {63820, 17556995}, {63821, 17557251}, {63822, 17557507}, {63823, 17557763}, + {63824, 17558019}, {63825, 17558275}, {63826, 17558531}, {63827, 17558787}, + {63828, 17559043}, {63829, 17559299}, {63830, 17559555}, {63831, 17559811}, + {63832, 17560067}, {63833, 17560323}, {63834, 17560579}, {63835, 17560835}, + {63836, 17543171}, {63837, 17561091}, {63838, 17561347}, {63839, 17561603}, + {63840, 17561859}, {63841, 17562115}, {63842, 17562371}, {63843, 17562627}, + {63844, 17562883}, {63845, 17563139}, {63846, 17563395}, {63847, 17563651}, + {63848, 17563907}, {63849, 17564163}, {63850, 17564419}, {63851, 17564675}, + {63852, 17564931}, {63853, 17565187}, {63854, 17565443}, {63855, 17565699}, + {63856, 17565955}, {63857, 17182467}, {63858, 17566211}, {63859, 17566467}, + {63860, 17566723}, {63861, 17566979}, {63862, 17567235}, {63863, 17567491}, + {63864, 17567747}, {63865, 17568003}, {63866, 17568259}, {63867, 17568515}, + {63868, 17568771}, {63869, 17569027}, {63870, 17569283}, {63871, 17569539}, + {63872, 17569795}, {63873, 17150979}, {63874, 17570051}, {63875, 17570307}, + {63876, 17570563}, {63877, 17570819}, {63878, 17571075}, {63879, 17571331}, + {63880, 17571587}, {63881, 17571843}, {63882, 17146115}, {63883, 17572099}, + {63884, 17572355}, {63885, 17572611}, {63886, 17572867}, {63887, 17573123}, + {63888, 17573379}, {63889, 17573635}, {63890, 17573891}, {63891, 17574147}, + {63892, 17574403}, {63893, 17574659}, {63894, 17574915}, {63895, 17575171}, + {63896, 17575427}, {63897, 17575683}, {63898, 17575939}, {63899, 17576195}, + {63900, 17576451}, {63901, 17576707}, {63902, 17576963}, {63903, 17577219}, + {63904, 17577475}, {63905, 17565699}, {63906, 17577731}, {63907, 17577987}, + {63908, 17578243}, {63909, 17578499}, {63910, 17578755}, {63911, 17579011}, + {63912, 17316867}, {63913, 17579267}, {63914, 17561603}, {63915, 17579523}, + {63916, 17579779}, {63917, 17580035}, {63918, 17580291}, {63919, 17580547}, + {63920, 17580803}, {63921, 17581059}, {63922, 17581315}, {63923, 17581571}, + {63924, 17581827}, {63925, 17582083}, {63926, 17582339}, {63927, 17582595}, + {63928, 17582851}, {63929, 17583107}, {63930, 17583363}, {63931, 17583619}, + {63932, 17583875}, {63933, 17584131}, {63934, 17584387}, {63935, 17543171}, + {63936, 17584643}, {63937, 17584899}, {63938, 17585155}, {63939, 17585411}, + {63940, 17195523}, {63941, 17585667}, {63942, 17585923}, {63943, 17586179}, + {63944, 17586435}, {63945, 17586691}, {63946, 17586947}, {63947, 17587203}, + {63948, 17587459}, {63949, 17587715}, {63950, 17587971}, {63951, 17588227}, + {63952, 17588483}, {63953, 17254147}, {63954, 17588739}, {63955, 17588995}, + {63956, 17589251}, {63957, 17589507}, {63958, 17589763}, {63959, 17590019}, + {63960, 17590275}, {63961, 17590531}, {63962, 17590787}, {63963, 17562115}, + {63964, 17591043}, {63965, 17591299}, {63966, 17591555}, {63967, 17591811}, + {63968, 17592067}, {63969, 17592323}, {63970, 17592579}, {63971, 17592835}, + {63972, 17593091}, {63973, 17593347}, {63974, 17593603}, {63975, 17593859}, + {63976, 17594115}, {63977, 17183747}, {63978, 17594371}, {63979, 17594627}, + {63980, 17594883}, {63981, 17595139}, {63982, 17595395}, {63983, 17595651}, + {63984, 17595907}, {63985, 17596163}, {63986, 17596419}, {63987, 17596675}, + {63988, 17596931}, {63989, 17597187}, {63990, 17597443}, {63991, 17171203}, + {63992, 17597699}, {63993, 17597955}, {63994, 17598211}, {63995, 17598467}, + {63996, 17598723}, {63997, 17598979}, {63998, 17599235}, {63999, 17599491}, + {64000, 17599747}, {64001, 17600003}, {64002, 17600259}, {64003, 17600515}, + {64004, 17600771}, {64005, 17601027}, {64006, 17601283}, {64007, 17601539}, + {64008, 17178115}, {64009, 17601795}, {64010, 17178883}, {64011, 17602051}, + {64012, 17602307}, {64013, 17602563}, {64014, 1}, {64016, 17602819}, + {64017, 1}, {64018, 17603075}, {64019, 1}, {64021, 17603331}, + {64022, 17603587}, {64023, 17603843}, {64024, 17604099}, {64025, 17604355}, + {64026, 17604611}, {64027, 17604867}, {64028, 17605123}, {64029, 17605379}, + {64030, 17172995}, {64031, 1}, {64032, 17605635}, {64033, 1}, + {64034, 17605891}, {64035, 1}, {64037, 17606147}, {64038, 17606403}, + {64039, 1}, {64042, 17606659}, {64043, 17606915}, {64044, 17607171}, + {64045, 17607427}, {64046, 17607683}, {64047, 17607939}, {64048, 17608195}, + {64049, 17608451}, {64050, 17608707}, {64051, 17608963}, {64052, 17609219}, + {64053, 17609475}, {64054, 17609731}, {64055, 17609987}, {64056, 17610243}, + {64057, 17610499}, {64058, 17610755}, {64059, 17611011}, {64060, 17152771}, + {64061, 17611267}, {64062, 17611523}, {64063, 17611779}, {64064, 17612035}, + {64065, 17612291}, {64066, 17612547}, {64067, 17612803}, {64068, 17613059}, + {64069, 17613315}, {64070, 17613571}, {64071, 17613827}, {64072, 17614083}, + {64073, 17614339}, {64074, 17614595}, {64075, 17614851}, {64076, 17264899}, + {64077, 17615107}, {64078, 17615363}, {64079, 17615619}, {64080, 17615875}, + {64081, 17267971}, {64082, 17616131}, {64083, 17616387}, {64084, 17616643}, + {64085, 17616899}, {64086, 17617155}, {64087, 17574915}, {64088, 17617411}, + {64089, 17617667}, {64090, 17617923}, {64091, 17618179}, {64092, 17618435}, + {64093, 17618691}, {64095, 17618947}, {64096, 17619203}, {64097, 17619459}, + {64098, 17619715}, {64099, 17619971}, {64100, 17620227}, {64101, 17620483}, + {64102, 17620739}, {64103, 17606147}, {64104, 17620995}, {64105, 17621251}, + {64106, 17621507}, {64107, 17621763}, {64108, 17622019}, {64109, 17622275}, + {64110, 2}, {64112, 17622531}, {64113, 17622787}, {64114, 17623043}, + {64115, 17623299}, {64116, 17623555}, {64117, 17623811}, {64118, 17624067}, + {64119, 17624323}, {64120, 17609731}, {64121, 17624579}, {64122, 17624835}, + {64123, 17625091}, {64124, 17602819}, {64125, 17625347}, {64126, 17625603}, + {64127, 17625859}, {64128, 17626115}, {64129, 17626371}, {64130, 17626627}, + {64131, 17626883}, {64132, 17627139}, {64133, 17627395}, {64134, 17627651}, + {64135, 17627907}, {64136, 17628163}, {64137, 17611779}, {64138, 17628419}, + {64139, 17612035}, {64140, 17628675}, {64141, 17628931}, {64142, 17629187}, + {64143, 17629443}, {64144, 17629699}, {64145, 17603075}, {64146, 17548547}, + {64147, 17629955}, {64148, 17630211}, {64149, 17161219}, {64150, 17565955}, + {64151, 17586947}, {64152, 17630467}, {64153, 17630723}, {64154, 17613827}, + {64155, 17630979}, {64156, 17614083}, {64157, 17631235}, {64158, 17631491}, + {64159, 17631747}, {64160, 17603587}, {64161, 17632003}, {64162, 17632259}, + {64163, 17632515}, {64164, 17632771}, {64165, 17633027}, {64166, 17603843}, + {64167, 17633283}, {64168, 17633539}, {64169, 17633795}, {64170, 17634051}, + {64171, 17634307}, {64172, 17634563}, {64173, 17617155}, {64174, 17634819}, + {64175, 17635075}, {64176, 17574915}, {64177, 17635331}, {64178, 17618179}, + {64179, 17635587}, {64180, 17635843}, {64181, 17636099}, {64182, 17636355}, + {64183, 17636611}, {64184, 17619459}, {64185, 17636867}, {64186, 17605891}, + {64187, 17637123}, {64188, 17619715}, {64189, 17561091}, {64190, 17637379}, + {64191, 17619971}, {64192, 17637635}, {64193, 17620483}, {64194, 17637891}, + {64195, 17638147}, {64196, 17638403}, {64197, 17638659}, {64198, 17638915}, + {64199, 17620995}, {64200, 17605123}, {64201, 17639171}, {64202, 17621251}, + {64203, 17639427}, {64204, 17621507}, {64205, 17639683}, {64206, 17195779}, + {64207, 17639939}, {64208, 17640195}, {64209, 17640451}, {64210, 17640707}, + {64211, 17640963}, {64212, 17641219}, {64213, 17641475}, {64214, 17641731}, + {64215, 17641987}, {64216, 17642243}, {64217, 17642499}, {64218, 2}, + {64256, 34419971}, {64257, 34420483}, {64258, 34420995}, {64259, 51197443}, + {64260, 51198723}, {64261, 33559043}, {64263, 2}, {64275, 34422275}, + {64276, 34422787}, {64277, 34423299}, {64278, 34423811}, {64279, 34424323}, + {64280, 2}, {64285, 34424835}, {64286, 1}, {64287, 34425347}, + {64288, 17648643}, {64289, 17043971}, {64290, 17044739}, {64291, 17648899}, + {64292, 17649155}, {64293, 17649411}, {64294, 17649667}, {64295, 17649923}, + {64296, 17650179}, {64297, 17036803}, {64298, 34427651}, {64299, 34428163}, + {64300, 51205891}, {64301, 51206659}, {64302, 34430211}, {64303, 34430723}, + {64304, 34431235}, {64305, 34431747}, {64306, 34432259}, {64307, 34432771}, + {64308, 34433283}, {64309, 34433795}, {64310, 34434307}, {64311, 2}, + {64312, 34434819}, {64313, 34435331}, {64314, 34435843}, {64315, 34436355}, + {64316, 34436867}, {64317, 2}, {64318, 34437379}, {64319, 2}, + {64320, 34437891}, {64321, 34438403}, {64322, 2}, {64323, 34438915}, + {64324, 34439427}, {64325, 2}, {64326, 34439939}, {64327, 34440451}, + {64328, 34440963}, {64329, 34428675}, {64330, 34441475}, {64331, 34441987}, + {64332, 34442499}, {64333, 34443011}, {64334, 34443523}, {64335, 34444035}, + {64336, 17667331}, {64338, 17667587}, {64342, 17667843}, {64346, 17668099}, + {64350, 17668355}, {64354, 17668611}, {64358, 17668867}, {64362, 17669123}, + {64366, 17669379}, {64370, 17669635}, {64374, 17669891}, {64378, 17670147}, + {64382, 17670403}, {64386, 17670659}, {64388, 17670915}, {64390, 17671171}, + {64392, 17671427}, {64394, 17671683}, {64396, 17671939}, {64398, 17672195}, + {64402, 17672451}, {64406, 17672707}, {64410, 17672963}, {64414, 17673219}, + {64416, 17673475}, {64420, 17673731}, {64422, 17673987}, {64426, 17674243}, + {64430, 17674499}, {64432, 17674755}, {64434, 1}, {64451, 2}, + {64467, 17675011}, {64471, 16911363}, {64473, 17675267}, {64475, 17675523}, + {64477, 33688579}, {64478, 17675779}, {64480, 17676035}, {64482, 17676291}, + {64484, 17676547}, {64488, 17676803}, {64490, 34454275}, {64492, 34454787}, + {64494, 34455299}, {64496, 34455811}, {64498, 34456323}, {64500, 34456835}, + {64502, 34457347}, {64505, 34457859}, {64508, 17681155}, {64512, 34458627}, + {64513, 34459139}, {64514, 34459651}, {64515, 34457859}, {64516, 34460163}, + {64517, 34460675}, {64518, 34461187}, {64519, 34461699}, {64520, 34462211}, + {64521, 34462723}, {64522, 34463235}, {64523, 34463747}, {64524, 34464259}, + {64525, 34464771}, {64526, 34465283}, {64527, 34465795}, {64528, 34466307}, + {64529, 34466819}, {64530, 34467331}, {64531, 34467843}, {64532, 34468355}, + {64533, 34468867}, {64534, 34469379}, {64535, 34469123}, {64536, 34469891}, + {64537, 34470403}, {64538, 34470915}, {64539, 34471427}, {64540, 34471939}, + {64541, 34472451}, {64542, 34472963}, {64543, 34473475}, {64544, 34473987}, + {64545, 34474499}, {64546, 34475011}, {64547, 34475523}, {64548, 34476035}, + {64549, 34476547}, {64550, 34477059}, {64551, 34477571}, {64552, 34478083}, + {64553, 34478595}, {64554, 34479107}, {64555, 34479619}, {64556, 34480131}, + {64557, 34480643}, {64558, 34481155}, {64559, 34481667}, {64560, 34482179}, + {64561, 34482691}, {64562, 34483203}, {64563, 34483715}, {64564, 34484227}, + {64565, 34484739}, {64566, 34485251}, {64567, 34485763}, {64568, 34486275}, + {64569, 34486787}, {64570, 34487299}, {64571, 34487811}, {64572, 34488323}, + {64573, 34488835}, {64574, 34489347}, {64575, 34489859}, {64576, 34490371}, + {64577, 34490883}, {64578, 34491395}, {64579, 34491907}, {64580, 34492419}, + {64581, 34492931}, {64582, 34469635}, {64583, 34470147}, {64584, 34493443}, + {64585, 34493955}, {64586, 34494467}, {64587, 34494979}, {64588, 34495491}, + {64589, 34496003}, {64590, 34496515}, {64591, 34497027}, {64592, 34497539}, + {64593, 34498051}, {64594, 34498563}, {64595, 34499075}, {64596, 34499587}, + {64597, 34468611}, {64598, 34500099}, {64599, 34500611}, {64600, 34492675}, + {64601, 34501123}, {64602, 34499843}, {64603, 34501635}, {64604, 34502147}, + {64605, 34502659}, {64606, 51280387}, {64607, 51281155}, {64608, 51281923}, + {64609, 51282691}, {64610, 51283459}, {64611, 51284227}, {64612, 34507779}, + {64613, 34508291}, {64614, 34459651}, {64615, 34508803}, {64616, 34457859}, + {64617, 34460163}, {64618, 34509315}, {64619, 34509827}, {64620, 34462211}, + {64621, 34510339}, {64622, 34462723}, {64623, 34463235}, {64624, 34510851}, + {64625, 34511363}, {64626, 34465283}, {64627, 34511875}, {64628, 34465795}, + {64629, 34466307}, {64630, 34512387}, {64631, 34512899}, {64632, 34467331}, + {64633, 34513411}, {64634, 34467843}, {64635, 34468355}, {64636, 34482691}, + {64637, 34483203}, {64638, 34484739}, {64639, 34485251}, {64640, 34485763}, + {64641, 34487811}, {64642, 34488323}, {64643, 34488835}, {64644, 34489347}, + {64645, 34491395}, {64646, 34491907}, {64647, 34492419}, {64648, 34513923}, + {64649, 34493443}, {64650, 34514435}, {64651, 34514947}, {64652, 34496515}, + {64653, 34515459}, {64654, 34497027}, {64655, 34497539}, {64656, 34502659}, + {64657, 34515971}, {64658, 34516483}, {64659, 34492675}, {64660, 34494723}, + {64661, 34501123}, {64662, 34499843}, {64663, 34458627}, {64664, 34459139}, + {64665, 34516995}, {64666, 34459651}, {64667, 34517507}, {64668, 34460675}, + {64669, 34461187}, {64670, 34461699}, {64671, 34462211}, {64672, 34518019}, + {64673, 34463747}, {64674, 34464259}, {64675, 34464771}, {64676, 34465283}, + {64677, 34518531}, {64678, 34467331}, {64679, 34468867}, {64680, 34469379}, + {64681, 34469123}, {64682, 34469891}, {64683, 34470403}, {64684, 34471427}, + {64685, 34471939}, {64686, 34472451}, {64687, 34472963}, {64688, 34473475}, + {64689, 34473987}, {64690, 34519043}, {64691, 34474499}, {64692, 34475011}, + {64693, 34475523}, {64694, 34476035}, {64695, 34476547}, {64696, 34477059}, + {64697, 34478083}, {64698, 34478595}, {64699, 34479107}, {64700, 34479619}, + {64701, 34480131}, {64702, 34480643}, {64703, 34481155}, {64704, 34481667}, + {64705, 34482179}, {64706, 34483715}, {64707, 34484227}, {64708, 34486275}, + {64709, 34486787}, {64710, 34487299}, {64711, 34487811}, {64712, 34488323}, + {64713, 34489859}, {64714, 34490371}, {64715, 34490883}, {64716, 34491395}, + {64717, 34519555}, {64718, 34492931}, {64719, 34469635}, {64720, 34470147}, + {64721, 34493443}, {64722, 34494979}, {64723, 34495491}, {64724, 34496003}, + {64725, 34496515}, {64726, 34520067}, {64727, 34498051}, {64728, 34498563}, + {64729, 34520579}, {64730, 34468611}, {64731, 34500099}, {64732, 34500611}, + {64733, 34492675}, {64734, 34497795}, {64735, 34459651}, {64736, 34517507}, + {64737, 34462211}, {64738, 34518019}, {64739, 34465283}, {64740, 34518531}, + {64741, 34467331}, {64742, 34521091}, {64743, 34473475}, {64744, 34521603}, + {64745, 34522115}, {64746, 34522627}, {64747, 34487811}, {64748, 34488323}, + {64749, 34491395}, {64750, 34496515}, {64751, 34520067}, {64752, 34492675}, + {64753, 34497795}, {64754, 51300355}, {64755, 51301123}, {64756, 51301891}, + {64757, 34525443}, {64758, 34525955}, {64759, 34526467}, {64760, 34526979}, + {64761, 34527491}, {64762, 34528003}, {64763, 34528515}, {64764, 34529027}, + {64765, 34529539}, {64766, 34530051}, {64767, 34530563}, {64768, 34500355}, + {64769, 34531075}, {64770, 34531587}, {64771, 34532099}, {64772, 34500867}, + {64773, 34532611}, {64774, 34533123}, {64775, 34533635}, {64776, 34534147}, + {64777, 34534659}, {64778, 34535171}, {64779, 34535683}, {64780, 34522115}, + {64781, 34536195}, {64782, 34536707}, {64783, 34537219}, {64784, 34537731}, + {64785, 34525443}, {64786, 34525955}, {64787, 34526467}, {64788, 34526979}, + {64789, 34527491}, {64790, 34528003}, {64791, 34528515}, {64792, 34529027}, + {64793, 34529539}, {64794, 34530051}, {64795, 34530563}, {64796, 34500355}, + {64797, 34531075}, {64798, 34531587}, {64799, 34532099}, {64800, 34500867}, + {64801, 34532611}, {64802, 34533123}, {64803, 34533635}, {64804, 34534147}, + {64805, 34534659}, {64806, 34535171}, {64807, 34535683}, {64808, 34522115}, + {64809, 34536195}, {64810, 34536707}, {64811, 34537219}, {64812, 34537731}, + {64813, 34534659}, {64814, 34535171}, {64815, 34535683}, {64816, 34522115}, + {64817, 34521603}, {64818, 34522627}, {64819, 34477571}, {64820, 34471939}, + {64821, 34472451}, {64822, 34472963}, {64823, 34534659}, {64824, 34535171}, + {64825, 34535683}, {64826, 34477571}, {64827, 34478083}, {64828, 34538243}, + {64830, 1}, {64848, 51315971}, {64849, 51316739}, {64851, 51317507}, + {64852, 51318275}, {64853, 51319043}, {64854, 51319811}, {64855, 51320579}, + {64856, 51246595}, {64858, 51321347}, {64859, 51322115}, {64860, 51322883}, + {64861, 51323651}, {64862, 51324419}, {64863, 51325187}, {64865, 51325955}, + {64866, 51326723}, {64868, 51327491}, {64870, 51328259}, {64871, 51329027}, + {64873, 51329795}, {64874, 51330563}, {64876, 51331331}, {64878, 51332099}, + {64879, 51332867}, {64881, 51333635}, {64883, 51334403}, {64884, 51335171}, + {64885, 51335939}, {64886, 51336707}, {64888, 51337475}, {64889, 51338243}, + {64890, 51339011}, {64891, 51339779}, {64892, 51340547}, {64894, 51341315}, + {64895, 51342083}, {64896, 51342851}, {64897, 51343619}, {64898, 51344387}, + {64899, 51345155}, {64901, 51345923}, {64903, 51346691}, {64905, 51347459}, + {64906, 51246851}, {64907, 51348227}, {64908, 51348995}, {64909, 51270147}, + {64910, 51247363}, {64911, 51349763}, {64912, 2}, {64914, 51350531}, + {64915, 51351299}, {64916, 51352067}, {64917, 51352835}, {64918, 51353603}, + {64919, 51354371}, {64921, 51355139}, {64922, 51355907}, {64923, 51356675}, + {64924, 51357443}, {64926, 51358211}, {64927, 51358979}, {64928, 51359747}, + {64929, 51360515}, {64930, 51361283}, {64931, 51362051}, {64932, 51362819}, + {64933, 51363587}, {64934, 51364355}, {64935, 51365123}, {64936, 51365891}, + {64937, 51366659}, {64938, 51367427}, {64939, 51368195}, {64940, 51368963}, + {64941, 51369731}, {64942, 51277315}, {64943, 51370499}, {64944, 51371267}, + {64945, 51372035}, {64946, 51372803}, {64947, 51373571}, {64948, 51341315}, + {64949, 51342851}, {64950, 51374339}, {64951, 51375107}, {64952, 51375875}, + {64953, 51376643}, {64954, 51377411}, {64955, 51378179}, {64956, 51377411}, + {64957, 51375875}, {64958, 51378947}, {64959, 51379715}, {64960, 51380483}, + {64961, 51381251}, {64962, 51382019}, {64963, 51378179}, {64964, 51335939}, + {64965, 51328259}, {64966, 51382787}, {64967, 51383555}, {64968, 2}, + {64975, 1}, {64976, 2}, {65008, 51384323}, {65009, 51385091}, + {65010, 68163075}, {65011, 68164099}, {65012, 68165123}, {65013, 68166147}, + {65014, 68167171}, {65015, 68168195}, {65016, 68169219}, {65017, 51393027}, + {65018, 303052035}, {65019, 135284483}, {65020, 68177667}, {65021, 1}, + {65024, 0}, {65040, 17847043}, {65041, 17847299}, {65042, 2}, + {65043, 17110275}, {65044, 16848643}, {65045, 17032707}, {65046, 17033731}, + {65047, 17847555}, {65048, 17847811}, {65049, 2}, {65056, 1}, + {65072, 2}, {65073, 17848067}, {65074, 17848323}, {65075, 17848579}, + {65077, 17037571}, {65078, 17037827}, {65079, 17848835}, {65080, 17849091}, + {65081, 17849347}, {65082, 17849603}, {65083, 17849859}, {65084, 17850115}, + {65085, 17850371}, {65086, 17850627}, {65087, 17067011}, {65088, 17067267}, + {65089, 17850883}, {65090, 17851139}, {65091, 17851395}, {65092, 17851651}, + {65093, 1}, {65095, 17851907}, {65096, 17852163}, {65097, 33810435}, + {65101, 17848579}, {65104, 17847043}, {65105, 17847299}, {65106, 2}, + {65108, 16848643}, {65109, 17110275}, {65110, 17033731}, {65111, 17032707}, + {65112, 17848067}, {65113, 17037571}, {65114, 17037827}, {65115, 17848835}, + {65116, 17849091}, {65117, 17849347}, {65118, 17849603}, {65119, 17852419}, + {65120, 17852675}, {65121, 17852931}, {65122, 17036803}, {65123, 17853187}, + {65124, 17853443}, {65125, 17853699}, {65126, 17037315}, {65127, 2}, + {65128, 17853955}, {65129, 17854211}, {65130, 17854467}, {65131, 17854723}, + {65132, 2}, {65136, 34632195}, {65137, 34632707}, {65138, 34503171}, + {65139, 1}, {65140, 34503939}, {65141, 2}, {65142, 34504707}, + {65143, 34523139}, {65144, 34505475}, {65145, 34523907}, {65146, 34506243}, + {65147, 34524675}, {65148, 34507011}, {65149, 34633219}, {65150, 34633731}, + {65151, 34634243}, {65152, 17857539}, {65153, 17857795}, {65155, 17858051}, + {65157, 17858307}, {65159, 17858563}, {65161, 17677059}, {65165, 16910339}, + {65167, 17683459}, {65171, 17858819}, {65173, 17686531}, {65177, 17689603}, + {65181, 17681667}, {65185, 17682179}, {65189, 17684739}, {65193, 17834243}, + {65195, 17724419}, {65197, 17724931}, {65199, 17731331}, {65201, 17694723}, + {65205, 17744899}, {65209, 17696771}, {65213, 17697795}, {65217, 17699843}, + {65221, 17700867}, {65225, 17701379}, {65229, 17702403}, {65233, 17703427}, + {65237, 17706499}, {65241, 17708547}, {65245, 17710851}, {65249, 17682691}, + {65253, 17717763}, {65257, 17720835}, {65261, 16910851}, {65263, 17676803}, + {65265, 16911875}, {65269, 34636291}, {65271, 34636803}, {65273, 34637315}, + {65275, 34622211}, {65277, 2}, {65279, 0}, {65280, 2}, + {65281, 17032707}, {65282, 17860611}, {65283, 17852419}, {65284, 17854211}, + {65285, 17854467}, {65286, 17852675}, {65287, 17860867}, {65288, 17037571}, + {65289, 17037827}, {65290, 17852931}, {65291, 17036803}, {65292, 17847043}, + {65293, 17853187}, {65294, 17196291}, {65295, 17038339}, {65296, 17035267}, + {65297, 16786947}, {65298, 16785155}, {65299, 16785411}, {65300, 16787715}, + {65301, 17035523}, {65302, 17035779}, {65303, 17036035}, {65304, 17036291}, + {65305, 17036547}, {65306, 17110275}, {65307, 16848643}, {65308, 17853443}, + {65309, 17037315}, {65310, 17853699}, {65311, 17033731}, {65312, 17854723}, + {65313, 16777219}, {65314, 16777475}, {65315, 16777731}, {65316, 16777987}, + {65317, 16778243}, {65318, 16778499}, {65319, 16778755}, {65320, 16779011}, + {65321, 16779267}, {65322, 16779523}, {65323, 16779779}, {65324, 16780035}, + {65325, 16780291}, {65326, 16780547}, {65327, 16780803}, {65328, 16781059}, + {65329, 16781315}, {65330, 16781571}, {65331, 16781827}, {65332, 16782083}, + {65333, 16782339}, {65334, 16782595}, {65335, 16782851}, {65336, 16783107}, + {65337, 16783363}, {65338, 16783619}, {65339, 17851907}, {65340, 17853955}, + {65341, 17852163}, {65342, 17861123}, {65343, 17848579}, {65344, 17026819}, + {65345, 16777219}, {65346, 16777475}, {65347, 16777731}, {65348, 16777987}, + {65349, 16778243}, {65350, 16778499}, {65351, 16778755}, {65352, 16779011}, + {65353, 16779267}, {65354, 16779523}, {65355, 16779779}, {65356, 16780035}, + {65357, 16780291}, {65358, 16780547}, {65359, 16780803}, {65360, 16781059}, + {65361, 16781315}, {65362, 16781571}, {65363, 16781827}, {65364, 16782083}, + {65365, 16782339}, {65366, 16782595}, {65367, 16782851}, {65368, 16783107}, + {65369, 16783363}, {65370, 16783619}, {65371, 17848835}, {65372, 17861379}, + {65373, 17849091}, {65374, 17861635}, {65375, 17861891}, {65376, 17862147}, + {65377, 17196291}, {65378, 17850883}, {65379, 17851139}, {65380, 17847299}, + {65381, 17862403}, {65382, 17316611}, {65383, 17319171}, {65384, 17362179}, + {65385, 17862659}, {65386, 17363715}, {65387, 17323267}, {65388, 17862915}, + {65389, 17333507}, {65390, 17379331}, {65391, 17328899}, {65392, 17317891}, + {65393, 17305347}, {65394, 17305603}, {65395, 17305859}, {65396, 17306115}, + {65397, 17306371}, {65398, 17306627}, {65399, 17306883}, {65400, 17307139}, + {65401, 17307395}, {65402, 17198851}, {65403, 17307651}, {65404, 17307907}, + {65405, 17308163}, {65406, 17308419}, {65407, 17308675}, {65408, 17308931}, + {65409, 17309187}, {65410, 17309443}, {65411, 17309699}, {65412, 17199107}, + {65413, 17309955}, {65414, 17310211}, {65415, 17310467}, {65416, 17310723}, + {65417, 17310979}, {65418, 17311235}, {65419, 17311491}, {65420, 17311747}, + {65421, 17312003}, {65422, 17312259}, {65423, 17312515}, {65424, 17312771}, + {65425, 17313027}, {65426, 17313283}, {65427, 17313539}, {65428, 17313795}, + {65429, 17314051}, {65430, 17314307}, {65431, 17314563}, {65432, 17314819}, + {65433, 17315075}, {65434, 17315331}, {65435, 17315587}, {65436, 17315843}, + {65437, 17319683}, {65438, 17197571}, {65439, 17198083}, {65440, 2}, + {65441, 17199363}, {65442, 17199619}, {65443, 17199875}, {65444, 17200131}, + {65445, 17200387}, {65446, 17200643}, {65447, 17200899}, {65448, 17201155}, + {65449, 17201411}, {65450, 17201667}, {65451, 17201923}, {65452, 17202179}, + {65453, 17202435}, {65454, 17202691}, {65455, 17202947}, {65456, 17203203}, + {65457, 17203459}, {65458, 17203715}, {65459, 17203971}, {65460, 17204227}, + {65461, 17204483}, {65462, 17204739}, {65463, 17204995}, {65464, 17205251}, + {65465, 17205507}, {65466, 17205763}, {65467, 17206019}, {65468, 17206275}, + {65469, 17206531}, {65470, 17206787}, {65471, 2}, {65474, 17207043}, + {65475, 17207299}, {65476, 17207555}, {65477, 17207811}, {65478, 17208067}, + {65479, 17208323}, {65480, 2}, {65482, 17208579}, {65483, 17208835}, + {65484, 17209091}, {65485, 17209347}, {65486, 17209603}, {65487, 17209859}, + {65488, 2}, {65490, 17210115}, {65491, 17210371}, {65492, 17210627}, + {65493, 17210883}, {65494, 17211139}, {65495, 17211395}, {65496, 2}, + {65498, 17211651}, {65499, 17211907}, {65500, 17212163}, {65501, 2}, + {65504, 17863171}, {65505, 17863427}, {65506, 17863683}, {65507, 33561859}, + {65508, 17863939}, {65509, 17864195}, {65510, 17864451}, {65511, 2}, + {65512, 17864707}, {65513, 17864963}, {65514, 17865219}, {65515, 17865475}, + {65516, 17865731}, {65517, 17865987}, {65518, 17866243}, {65519, 2}, + {65536, 1}, {65548, 2}, {65549, 1}, {65575, 2}, + {65576, 1}, {65595, 2}, {65596, 1}, {65598, 2}, + {65599, 1}, {65614, 2}, {65616, 1}, {65630, 2}, + {65664, 1}, {65787, 2}, {65792, 1}, {65795, 2}, + {65799, 1}, {65844, 2}, {65847, 1}, {65935, 2}, + {65936, 1}, {65949, 2}, {65952, 1}, {65953, 2}, + {66000, 1}, {66046, 2}, {66176, 1}, {66205, 2}, + {66208, 1}, {66257, 2}, {66272, 1}, {66300, 2}, + {66304, 1}, {66340, 2}, {66349, 1}, {66379, 2}, + {66384, 1}, {66427, 2}, {66432, 1}, {66462, 2}, + {66463, 1}, {66500, 2}, {66504, 1}, {66518, 2}, + {66560, 17866499}, {66561, 17866755}, {66562, 17867011}, {66563, 17867267}, + {66564, 17867523}, {66565, 17867779}, {66566, 17868035}, {66567, 17868291}, + {66568, 17868547}, {66569, 17868803}, {66570, 17869059}, {66571, 17869315}, + {66572, 17869571}, {66573, 17869827}, {66574, 17870083}, {66575, 17870339}, + {66576, 17870595}, {66577, 17870851}, {66578, 17871107}, {66579, 17871363}, + {66580, 17871619}, {66581, 17871875}, {66582, 17872131}, {66583, 17872387}, + {66584, 17872643}, {66585, 17872899}, {66586, 17873155}, {66587, 17873411}, + {66588, 17873667}, {66589, 17873923}, {66590, 17874179}, {66591, 17874435}, + {66592, 17874691}, {66593, 17874947}, {66594, 17875203}, {66595, 17875459}, + {66596, 17875715}, {66597, 17875971}, {66598, 17876227}, {66599, 17876483}, + {66600, 1}, {66718, 2}, {66720, 1}, {66730, 2}, + {66736, 17876739}, {66737, 17876995}, {66738, 17877251}, {66739, 17877507}, + {66740, 17877763}, {66741, 17878019}, {66742, 17878275}, {66743, 17878531}, + {66744, 17878787}, {66745, 17879043}, {66746, 17879299}, {66747, 17879555}, + {66748, 17879811}, {66749, 17880067}, {66750, 17880323}, {66751, 17880579}, + {66752, 17880835}, {66753, 17881091}, {66754, 17881347}, {66755, 17881603}, + {66756, 17881859}, {66757, 17882115}, {66758, 17882371}, {66759, 17882627}, + {66760, 17882883}, {66761, 17883139}, {66762, 17883395}, {66763, 17883651}, + {66764, 17883907}, {66765, 17884163}, {66766, 17884419}, {66767, 17884675}, + {66768, 17884931}, {66769, 17885187}, {66770, 17885443}, {66771, 17885699}, + {66772, 2}, {66776, 1}, {66812, 2}, {66816, 1}, + {66856, 2}, {66864, 1}, {66916, 2}, {66927, 1}, + {66928, 17885955}, {66929, 17886211}, {66930, 17886467}, {66931, 17886723}, + {66932, 17886979}, {66933, 17887235}, {66934, 17887491}, {66935, 17887747}, + {66936, 17888003}, {66937, 17888259}, {66938, 17888515}, {66939, 2}, + {66940, 17888771}, {66941, 17889027}, {66942, 17889283}, {66943, 17889539}, + {66944, 17889795}, {66945, 17890051}, {66946, 17890307}, {66947, 17890563}, + {66948, 17890819}, {66949, 17891075}, {66950, 17891331}, {66951, 17891587}, + {66952, 17891843}, {66953, 17892099}, {66954, 17892355}, {66955, 2}, + {66956, 17892611}, {66957, 17892867}, {66958, 17893123}, {66959, 17893379}, + {66960, 17893635}, {66961, 17893891}, {66962, 17894147}, {66963, 2}, + {66964, 17894403}, {66965, 17894659}, {66966, 2}, {66967, 1}, + {66978, 2}, {66979, 1}, {66994, 2}, {66995, 1}, + {67002, 2}, {67003, 1}, {67005, 2}, {67072, 1}, + {67383, 2}, {67392, 1}, {67414, 2}, {67424, 1}, + {67432, 2}, {67456, 1}, {67457, 17894915}, {67458, 17895171}, + {67459, 16791043}, {67460, 17895427}, {67461, 16814083}, {67462, 2}, + {67463, 17895683}, {67464, 17895939}, {67465, 17896195}, {67466, 17896451}, + {67467, 16815363}, {67468, 16815619}, {67469, 17896707}, {67470, 17896963}, + {67471, 17897219}, {67472, 17897475}, {67473, 17897731}, {67474, 17897987}, + {67475, 16817155}, {67476, 17898243}, {67477, 16802051}, {67478, 17898499}, + {67479, 17898755}, {67480, 17899011}, {67481, 17899267}, {67482, 17899523}, + {67483, 17512707}, {67484, 17899779}, {67485, 17900035}, {67486, 17900291}, + {67487, 17900547}, {67488, 17900803}, {67489, 17901059}, {67490, 16795395}, + {67491, 17901315}, {67492, 17901571}, {67493, 16781315}, {67494, 17901827}, + {67495, 17902083}, {67496, 17125123}, {67497, 17902339}, {67498, 16819971}, + {67499, 17902595}, {67500, 17902851}, {67501, 17903107}, {67502, 17903363}, + {67503, 16820995}, {67504, 17903619}, {67505, 2}, {67506, 17903875}, + {67507, 17904131}, {67508, 17904387}, {67509, 17904643}, {67510, 17904899}, + {67511, 17905155}, {67512, 17905411}, {67513, 17905667}, {67514, 17905923}, + {67515, 2}, {67584, 1}, {67590, 2}, {67592, 1}, + {67593, 2}, {67594, 1}, {67638, 2}, {67639, 1}, + {67641, 2}, {67644, 1}, {67645, 2}, {67647, 1}, + {67670, 2}, {67671, 1}, {67743, 2}, {67751, 1}, + {67760, 2}, {67808, 1}, {67827, 2}, {67828, 1}, + {67830, 2}, {67835, 1}, {67868, 2}, {67871, 1}, + {67898, 2}, {67903, 1}, {67904, 2}, {67968, 1}, + {68024, 2}, {68028, 1}, {68048, 2}, {68050, 1}, + {68100, 2}, {68101, 1}, {68103, 2}, {68108, 1}, + {68116, 2}, {68117, 1}, {68120, 2}, {68121, 1}, + {68150, 2}, {68152, 1}, {68155, 2}, {68159, 1}, + {68169, 2}, {68176, 1}, {68185, 2}, {68192, 1}, + {68256, 2}, {68288, 1}, {68327, 2}, {68331, 1}, + {68343, 2}, {68352, 1}, {68406, 2}, {68409, 1}, + {68438, 2}, {68440, 1}, {68467, 2}, {68472, 1}, + {68498, 2}, {68505, 1}, {68509, 2}, {68521, 1}, + {68528, 2}, {68608, 1}, {68681, 2}, {68736, 17906179}, + {68737, 17906435}, {68738, 17906691}, {68739, 17906947}, {68740, 17907203}, + {68741, 17907459}, {68742, 17907715}, {68743, 17907971}, {68744, 17908227}, + {68745, 17908483}, {68746, 17908739}, {68747, 17908995}, {68748, 17909251}, + {68749, 17909507}, {68750, 17909763}, {68751, 17910019}, {68752, 17910275}, + {68753, 17910531}, {68754, 17910787}, {68755, 17911043}, {68756, 17911299}, + {68757, 17911555}, {68758, 17911811}, {68759, 17912067}, {68760, 17912323}, + {68761, 17912579}, {68762, 17912835}, {68763, 17913091}, {68764, 17913347}, + {68765, 17913603}, {68766, 17913859}, {68767, 17914115}, {68768, 17914371}, + {68769, 17914627}, {68770, 17914883}, {68771, 17915139}, {68772, 17915395}, + {68773, 17915651}, {68774, 17915907}, {68775, 17916163}, {68776, 17916419}, + {68777, 17916675}, {68778, 17916931}, {68779, 17917187}, {68780, 17917443}, + {68781, 17917699}, {68782, 17917955}, {68783, 17918211}, {68784, 17918467}, + {68785, 17918723}, {68786, 17918979}, {68787, 2}, {68800, 1}, + {68851, 2}, {68858, 1}, {68904, 2}, {68912, 1}, + {68922, 2}, {69216, 1}, {69247, 2}, {69248, 1}, + {69290, 2}, {69291, 1}, {69294, 2}, {69296, 1}, + {69298, 2}, {69373, 1}, {69416, 2}, {69424, 1}, + {69466, 2}, {69488, 1}, {69514, 2}, {69552, 1}, + {69580, 2}, {69600, 1}, {69623, 2}, {69632, 1}, + {69710, 2}, {69714, 1}, {69750, 2}, {69759, 1}, + {69821, 2}, {69822, 1}, {69827, 2}, {69840, 1}, + {69865, 2}, {69872, 1}, {69882, 2}, {69888, 1}, + {69941, 2}, {69942, 1}, {69960, 2}, {69968, 1}, + {70007, 2}, {70016, 1}, {70112, 2}, {70113, 1}, + {70133, 2}, {70144, 1}, {70162, 2}, {70163, 1}, + {70210, 2}, {70272, 1}, {70279, 2}, {70280, 1}, + {70281, 2}, {70282, 1}, {70286, 2}, {70287, 1}, + {70302, 2}, {70303, 1}, {70314, 2}, {70320, 1}, + {70379, 2}, {70384, 1}, {70394, 2}, {70400, 1}, + {70404, 2}, {70405, 1}, {70413, 2}, {70415, 1}, + {70417, 2}, {70419, 1}, {70441, 2}, {70442, 1}, + {70449, 2}, {70450, 1}, {70452, 2}, {70453, 1}, + {70458, 2}, {70459, 1}, {70469, 2}, {70471, 1}, + {70473, 2}, {70475, 1}, {70478, 2}, {70480, 1}, + {70481, 2}, {70487, 1}, {70488, 2}, {70493, 1}, + {70500, 2}, {70502, 1}, {70509, 2}, {70512, 1}, + {70517, 2}, {70656, 1}, {70748, 2}, {70749, 1}, + {70754, 2}, {70784, 1}, {70856, 2}, {70864, 1}, + {70874, 2}, {71040, 1}, {71094, 2}, {71096, 1}, + {71134, 2}, {71168, 1}, {71237, 2}, {71248, 1}, + {71258, 2}, {71264, 1}, {71277, 2}, {71296, 1}, + {71354, 2}, {71360, 1}, {71370, 2}, {71424, 1}, + {71451, 2}, {71453, 1}, {71468, 2}, {71472, 1}, + {71495, 2}, {71680, 1}, {71740, 2}, {71840, 17919235}, + {71841, 17919491}, {71842, 17919747}, {71843, 17920003}, {71844, 17920259}, + {71845, 17920515}, {71846, 17920771}, {71847, 17921027}, {71848, 17921283}, + {71849, 17921539}, {71850, 17921795}, {71851, 17922051}, {71852, 17922307}, + {71853, 17922563}, {71854, 17922819}, {71855, 17923075}, {71856, 17923331}, + {71857, 17923587}, {71858, 17923843}, {71859, 17924099}, {71860, 17924355}, + {71861, 17924611}, {71862, 17924867}, {71863, 17925123}, {71864, 17925379}, + {71865, 17925635}, {71866, 17925891}, {71867, 17926147}, {71868, 17926403}, + {71869, 17926659}, {71870, 17926915}, {71871, 17927171}, {71872, 1}, + {71923, 2}, {71935, 1}, {71943, 2}, {71945, 1}, + {71946, 2}, {71948, 1}, {71956, 2}, {71957, 1}, + {71959, 2}, {71960, 1}, {71990, 2}, {71991, 1}, + {71993, 2}, {71995, 1}, {72007, 2}, {72016, 1}, + {72026, 2}, {72096, 1}, {72104, 2}, {72106, 1}, + {72152, 2}, {72154, 1}, {72165, 2}, {72192, 1}, + {72264, 2}, {72272, 1}, {72355, 2}, {72368, 1}, + {72441, 2}, {72448, 1}, {72458, 2}, {72704, 1}, + {72713, 2}, {72714, 1}, {72759, 2}, {72760, 1}, + {72774, 2}, {72784, 1}, {72813, 2}, {72816, 1}, + {72848, 2}, {72850, 1}, {72872, 2}, {72873, 1}, + {72887, 2}, {72960, 1}, {72967, 2}, {72968, 1}, + {72970, 2}, {72971, 1}, {73015, 2}, {73018, 1}, + {73019, 2}, {73020, 1}, {73022, 2}, {73023, 1}, + {73032, 2}, {73040, 1}, {73050, 2}, {73056, 1}, + {73062, 2}, {73063, 1}, {73065, 2}, {73066, 1}, + {73103, 2}, {73104, 1}, {73106, 2}, {73107, 1}, + {73113, 2}, {73120, 1}, {73130, 2}, {73440, 1}, + {73465, 2}, {73472, 1}, {73489, 2}, {73490, 1}, + {73531, 2}, {73534, 1}, {73562, 2}, {73648, 1}, + {73649, 2}, {73664, 1}, {73714, 2}, {73727, 1}, + {74650, 2}, {74752, 1}, {74863, 2}, {74864, 1}, + {74869, 2}, {74880, 1}, {75076, 2}, {77712, 1}, + {77811, 2}, {77824, 1}, {78896, 2}, {78912, 1}, + {78934, 2}, {82944, 1}, {83527, 2}, {92160, 1}, + {92729, 2}, {92736, 1}, {92767, 2}, {92768, 1}, + {92778, 2}, {92782, 1}, {92863, 2}, {92864, 1}, + {92874, 2}, {92880, 1}, {92910, 2}, {92912, 1}, + {92918, 2}, {92928, 1}, {92998, 2}, {93008, 1}, + {93018, 2}, {93019, 1}, {93026, 2}, {93027, 1}, + {93048, 2}, {93053, 1}, {93072, 2}, {93760, 17927427}, + {93761, 17927683}, {93762, 17927939}, {93763, 17928195}, {93764, 17928451}, + {93765, 17928707}, {93766, 17928963}, {93767, 17929219}, {93768, 17929475}, + {93769, 17929731}, {93770, 17929987}, {93771, 17930243}, {93772, 17930499}, + {93773, 17930755}, {93774, 17931011}, {93775, 17931267}, {93776, 17931523}, + {93777, 17931779}, {93778, 17932035}, {93779, 17932291}, {93780, 17932547}, + {93781, 17932803}, {93782, 17933059}, {93783, 17933315}, {93784, 17933571}, + {93785, 17933827}, {93786, 17934083}, {93787, 17934339}, {93788, 17934595}, + {93789, 17934851}, {93790, 17935107}, {93791, 17935363}, {93792, 1}, + {93851, 2}, {93952, 1}, {94027, 2}, {94031, 1}, + {94088, 2}, {94095, 1}, {94112, 2}, {94176, 1}, + {94181, 2}, {94192, 1}, {94194, 2}, {94208, 1}, + {100344, 2}, {100352, 1}, {101590, 2}, {101632, 1}, + {101641, 2}, {110576, 1}, {110580, 2}, {110581, 1}, + {110588, 2}, {110589, 1}, {110591, 2}, {110592, 1}, + {110883, 2}, {110898, 1}, {110899, 2}, {110928, 1}, + {110931, 2}, {110933, 1}, {110934, 2}, {110948, 1}, + {110952, 2}, {110960, 1}, {111356, 2}, {113664, 1}, + {113771, 2}, {113776, 1}, {113789, 2}, {113792, 1}, + {113801, 2}, {113808, 1}, {113818, 2}, {113820, 1}, + {113824, 0}, {113828, 2}, {118528, 1}, {118574, 2}, + {118576, 1}, {118599, 2}, {118608, 1}, {118724, 2}, + {118784, 1}, {119030, 2}, {119040, 1}, {119079, 2}, + {119081, 1}, {119134, 34712835}, {119135, 34713347}, {119136, 51491075}, + {119137, 51491843}, {119138, 51492611}, {119139, 51493379}, {119140, 51494147}, + {119141, 1}, {119155, 2}, {119163, 1}, {119227, 34717699}, + {119228, 34718211}, {119229, 51495939}, {119230, 51496707}, {119231, 51497475}, + {119232, 51498243}, {119233, 1}, {119275, 2}, {119296, 1}, + {119366, 2}, {119488, 1}, {119508, 2}, {119520, 1}, + {119540, 2}, {119552, 1}, {119639, 2}, {119648, 1}, + {119673, 2}, {119808, 16777219}, {119809, 16777475}, {119810, 16777731}, + {119811, 16777987}, {119812, 16778243}, {119813, 16778499}, {119814, 16778755}, + {119815, 16779011}, {119816, 16779267}, {119817, 16779523}, {119818, 16779779}, + {119819, 16780035}, {119820, 16780291}, {119821, 16780547}, {119822, 16780803}, + {119823, 16781059}, {119824, 16781315}, {119825, 16781571}, {119826, 16781827}, + {119827, 16782083}, {119828, 16782339}, {119829, 16782595}, {119830, 16782851}, + {119831, 16783107}, {119832, 16783363}, {119833, 16783619}, {119834, 16777219}, + {119835, 16777475}, {119836, 16777731}, {119837, 16777987}, {119838, 16778243}, + {119839, 16778499}, {119840, 16778755}, {119841, 16779011}, {119842, 16779267}, + {119843, 16779523}, {119844, 16779779}, {119845, 16780035}, {119846, 16780291}, + {119847, 16780547}, {119848, 16780803}, {119849, 16781059}, {119850, 16781315}, + {119851, 16781571}, {119852, 16781827}, {119853, 16782083}, {119854, 16782339}, + {119855, 16782595}, {119856, 16782851}, {119857, 16783107}, {119858, 16783363}, + {119859, 16783619}, {119860, 16777219}, {119861, 16777475}, {119862, 16777731}, + {119863, 16777987}, {119864, 16778243}, {119865, 16778499}, {119866, 16778755}, + {119867, 16779011}, {119868, 16779267}, {119869, 16779523}, {119870, 16779779}, + {119871, 16780035}, {119872, 16780291}, {119873, 16780547}, {119874, 16780803}, + {119875, 16781059}, {119876, 16781315}, {119877, 16781571}, {119878, 16781827}, + {119879, 16782083}, {119880, 16782339}, {119881, 16782595}, {119882, 16782851}, + {119883, 16783107}, {119884, 16783363}, {119885, 16783619}, {119886, 16777219}, + {119887, 16777475}, {119888, 16777731}, {119889, 16777987}, {119890, 16778243}, + {119891, 16778499}, {119892, 16778755}, {119893, 2}, {119894, 16779267}, + {119895, 16779523}, {119896, 16779779}, {119897, 16780035}, {119898, 16780291}, + {119899, 16780547}, {119900, 16780803}, {119901, 16781059}, {119902, 16781315}, + {119903, 16781571}, {119904, 16781827}, {119905, 16782083}, {119906, 16782339}, + {119907, 16782595}, {119908, 16782851}, {119909, 16783107}, {119910, 16783363}, + {119911, 16783619}, {119912, 16777219}, {119913, 16777475}, {119914, 16777731}, + {119915, 16777987}, {119916, 16778243}, {119917, 16778499}, {119918, 16778755}, + {119919, 16779011}, {119920, 16779267}, {119921, 16779523}, {119922, 16779779}, + {119923, 16780035}, {119924, 16780291}, {119925, 16780547}, {119926, 16780803}, + {119927, 16781059}, {119928, 16781315}, {119929, 16781571}, {119930, 16781827}, + {119931, 16782083}, {119932, 16782339}, {119933, 16782595}, {119934, 16782851}, + {119935, 16783107}, {119936, 16783363}, {119937, 16783619}, {119938, 16777219}, + {119939, 16777475}, {119940, 16777731}, {119941, 16777987}, {119942, 16778243}, + {119943, 16778499}, {119944, 16778755}, {119945, 16779011}, {119946, 16779267}, + {119947, 16779523}, {119948, 16779779}, {119949, 16780035}, {119950, 16780291}, + {119951, 16780547}, {119952, 16780803}, {119953, 16781059}, {119954, 16781315}, + {119955, 16781571}, {119956, 16781827}, {119957, 16782083}, {119958, 16782339}, + {119959, 16782595}, {119960, 16782851}, {119961, 16783107}, {119962, 16783363}, + {119963, 16783619}, {119964, 16777219}, {119965, 2}, {119966, 16777731}, + {119967, 16777987}, {119968, 2}, {119970, 16778755}, {119971, 2}, + {119973, 16779523}, {119974, 16779779}, {119975, 2}, {119977, 16780547}, + {119978, 16780803}, {119979, 16781059}, {119980, 16781315}, {119981, 2}, + {119982, 16781827}, {119983, 16782083}, {119984, 16782339}, {119985, 16782595}, + {119986, 16782851}, {119987, 16783107}, {119988, 16783363}, {119989, 16783619}, + {119990, 16777219}, {119991, 16777475}, {119992, 16777731}, {119993, 16777987}, + {119994, 2}, {119995, 16778499}, {119996, 2}, {119997, 16779011}, + {119998, 16779267}, {119999, 16779523}, {120000, 16779779}, {120001, 16780035}, + {120002, 16780291}, {120003, 16780547}, {120004, 2}, {120005, 16781059}, + {120006, 16781315}, {120007, 16781571}, {120008, 16781827}, {120009, 16782083}, + {120010, 16782339}, {120011, 16782595}, {120012, 16782851}, {120013, 16783107}, + {120014, 16783363}, {120015, 16783619}, {120016, 16777219}, {120017, 16777475}, + {120018, 16777731}, {120019, 16777987}, {120020, 16778243}, {120021, 16778499}, + {120022, 16778755}, {120023, 16779011}, {120024, 16779267}, {120025, 16779523}, + {120026, 16779779}, {120027, 16780035}, {120028, 16780291}, {120029, 16780547}, + {120030, 16780803}, {120031, 16781059}, {120032, 16781315}, {120033, 16781571}, + {120034, 16781827}, {120035, 16782083}, {120036, 16782339}, {120037, 16782595}, + {120038, 16782851}, {120039, 16783107}, {120040, 16783363}, {120041, 16783619}, + {120042, 16777219}, {120043, 16777475}, {120044, 16777731}, {120045, 16777987}, + {120046, 16778243}, {120047, 16778499}, {120048, 16778755}, {120049, 16779011}, + {120050, 16779267}, {120051, 16779523}, {120052, 16779779}, {120053, 16780035}, + {120054, 16780291}, {120055, 16780547}, {120056, 16780803}, {120057, 16781059}, + {120058, 16781315}, {120059, 16781571}, {120060, 16781827}, {120061, 16782083}, + {120062, 16782339}, {120063, 16782595}, {120064, 16782851}, {120065, 16783107}, + {120066, 16783363}, {120067, 16783619}, {120068, 16777219}, {120069, 16777475}, + {120070, 2}, {120071, 16777987}, {120072, 16778243}, {120073, 16778499}, + {120074, 16778755}, {120075, 2}, {120077, 16779523}, {120078, 16779779}, + {120079, 16780035}, {120080, 16780291}, {120081, 16780547}, {120082, 16780803}, + {120083, 16781059}, {120084, 16781315}, {120085, 2}, {120086, 16781827}, + {120087, 16782083}, {120088, 16782339}, {120089, 16782595}, {120090, 16782851}, + {120091, 16783107}, {120092, 16783363}, {120093, 2}, {120094, 16777219}, + {120095, 16777475}, {120096, 16777731}, {120097, 16777987}, {120098, 16778243}, + {120099, 16778499}, {120100, 16778755}, {120101, 16779011}, {120102, 16779267}, + {120103, 16779523}, {120104, 16779779}, {120105, 16780035}, {120106, 16780291}, + {120107, 16780547}, {120108, 16780803}, {120109, 16781059}, {120110, 16781315}, + {120111, 16781571}, {120112, 16781827}, {120113, 16782083}, {120114, 16782339}, + {120115, 16782595}, {120116, 16782851}, {120117, 16783107}, {120118, 16783363}, + {120119, 16783619}, {120120, 16777219}, {120121, 16777475}, {120122, 2}, + {120123, 16777987}, {120124, 16778243}, {120125, 16778499}, {120126, 16778755}, + {120127, 2}, {120128, 16779267}, {120129, 16779523}, {120130, 16779779}, + {120131, 16780035}, {120132, 16780291}, {120133, 2}, {120134, 16780803}, + {120135, 2}, {120138, 16781827}, {120139, 16782083}, {120140, 16782339}, + {120141, 16782595}, {120142, 16782851}, {120143, 16783107}, {120144, 16783363}, + {120145, 2}, {120146, 16777219}, {120147, 16777475}, {120148, 16777731}, + {120149, 16777987}, {120150, 16778243}, {120151, 16778499}, {120152, 16778755}, + {120153, 16779011}, {120154, 16779267}, {120155, 16779523}, {120156, 16779779}, + {120157, 16780035}, {120158, 16780291}, {120159, 16780547}, {120160, 16780803}, + {120161, 16781059}, {120162, 16781315}, {120163, 16781571}, {120164, 16781827}, + {120165, 16782083}, {120166, 16782339}, {120167, 16782595}, {120168, 16782851}, + {120169, 16783107}, {120170, 16783363}, {120171, 16783619}, {120172, 16777219}, + {120173, 16777475}, {120174, 16777731}, {120175, 16777987}, {120176, 16778243}, + {120177, 16778499}, {120178, 16778755}, {120179, 16779011}, {120180, 16779267}, + {120181, 16779523}, {120182, 16779779}, {120183, 16780035}, {120184, 16780291}, + {120185, 16780547}, {120186, 16780803}, {120187, 16781059}, {120188, 16781315}, + {120189, 16781571}, {120190, 16781827}, {120191, 16782083}, {120192, 16782339}, + {120193, 16782595}, {120194, 16782851}, {120195, 16783107}, {120196, 16783363}, + {120197, 16783619}, {120198, 16777219}, {120199, 16777475}, {120200, 16777731}, + {120201, 16777987}, {120202, 16778243}, {120203, 16778499}, {120204, 16778755}, + {120205, 16779011}, {120206, 16779267}, {120207, 16779523}, {120208, 16779779}, + {120209, 16780035}, {120210, 16780291}, {120211, 16780547}, {120212, 16780803}, + {120213, 16781059}, {120214, 16781315}, {120215, 16781571}, {120216, 16781827}, + {120217, 16782083}, {120218, 16782339}, {120219, 16782595}, {120220, 16782851}, + {120221, 16783107}, {120222, 16783363}, {120223, 16783619}, {120224, 16777219}, + {120225, 16777475}, {120226, 16777731}, {120227, 16777987}, {120228, 16778243}, + {120229, 16778499}, {120230, 16778755}, {120231, 16779011}, {120232, 16779267}, + {120233, 16779523}, {120234, 16779779}, {120235, 16780035}, {120236, 16780291}, + {120237, 16780547}, {120238, 16780803}, {120239, 16781059}, {120240, 16781315}, + {120241, 16781571}, {120242, 16781827}, {120243, 16782083}, {120244, 16782339}, + {120245, 16782595}, {120246, 16782851}, {120247, 16783107}, {120248, 16783363}, + {120249, 16783619}, {120250, 16777219}, {120251, 16777475}, {120252, 16777731}, + {120253, 16777987}, {120254, 16778243}, {120255, 16778499}, {120256, 16778755}, + {120257, 16779011}, {120258, 16779267}, {120259, 16779523}, {120260, 16779779}, + {120261, 16780035}, {120262, 16780291}, {120263, 16780547}, {120264, 16780803}, + {120265, 16781059}, {120266, 16781315}, {120267, 16781571}, {120268, 16781827}, + {120269, 16782083}, {120270, 16782339}, {120271, 16782595}, {120272, 16782851}, + {120273, 16783107}, {120274, 16783363}, {120275, 16783619}, {120276, 16777219}, + {120277, 16777475}, {120278, 16777731}, {120279, 16777987}, {120280, 16778243}, + {120281, 16778499}, {120282, 16778755}, {120283, 16779011}, {120284, 16779267}, + {120285, 16779523}, {120286, 16779779}, {120287, 16780035}, {120288, 16780291}, + {120289, 16780547}, {120290, 16780803}, {120291, 16781059}, {120292, 16781315}, + {120293, 16781571}, {120294, 16781827}, {120295, 16782083}, {120296, 16782339}, + {120297, 16782595}, {120298, 16782851}, {120299, 16783107}, {120300, 16783363}, + {120301, 16783619}, {120302, 16777219}, {120303, 16777475}, {120304, 16777731}, + {120305, 16777987}, {120306, 16778243}, {120307, 16778499}, {120308, 16778755}, + {120309, 16779011}, {120310, 16779267}, {120311, 16779523}, {120312, 16779779}, + {120313, 16780035}, {120314, 16780291}, {120315, 16780547}, {120316, 16780803}, + {120317, 16781059}, {120318, 16781315}, {120319, 16781571}, {120320, 16781827}, + {120321, 16782083}, {120322, 16782339}, {120323, 16782595}, {120324, 16782851}, + {120325, 16783107}, {120326, 16783363}, {120327, 16783619}, {120328, 16777219}, + {120329, 16777475}, {120330, 16777731}, {120331, 16777987}, {120332, 16778243}, + {120333, 16778499}, {120334, 16778755}, {120335, 16779011}, {120336, 16779267}, + {120337, 16779523}, {120338, 16779779}, {120339, 16780035}, {120340, 16780291}, + {120341, 16780547}, {120342, 16780803}, {120343, 16781059}, {120344, 16781315}, + {120345, 16781571}, {120346, 16781827}, {120347, 16782083}, {120348, 16782339}, + {120349, 16782595}, {120350, 16782851}, {120351, 16783107}, {120352, 16783363}, + {120353, 16783619}, {120354, 16777219}, {120355, 16777475}, {120356, 16777731}, + {120357, 16777987}, {120358, 16778243}, {120359, 16778499}, {120360, 16778755}, + {120361, 16779011}, {120362, 16779267}, {120363, 16779523}, {120364, 16779779}, + {120365, 16780035}, {120366, 16780291}, {120367, 16780547}, {120368, 16780803}, + {120369, 16781059}, {120370, 16781315}, {120371, 16781571}, {120372, 16781827}, + {120373, 16782083}, {120374, 16782339}, {120375, 16782595}, {120376, 16782851}, + {120377, 16783107}, {120378, 16783363}, {120379, 16783619}, {120380, 16777219}, + {120381, 16777475}, {120382, 16777731}, {120383, 16777987}, {120384, 16778243}, + {120385, 16778499}, {120386, 16778755}, {120387, 16779011}, {120388, 16779267}, + {120389, 16779523}, {120390, 16779779}, {120391, 16780035}, {120392, 16780291}, + {120393, 16780547}, {120394, 16780803}, {120395, 16781059}, {120396, 16781315}, + {120397, 16781571}, {120398, 16781827}, {120399, 16782083}, {120400, 16782339}, + {120401, 16782595}, {120402, 16782851}, {120403, 16783107}, {120404, 16783363}, + {120405, 16783619}, {120406, 16777219}, {120407, 16777475}, {120408, 16777731}, + {120409, 16777987}, {120410, 16778243}, {120411, 16778499}, {120412, 16778755}, + {120413, 16779011}, {120414, 16779267}, {120415, 16779523}, {120416, 16779779}, + {120417, 16780035}, {120418, 16780291}, {120419, 16780547}, {120420, 16780803}, + {120421, 16781059}, {120422, 16781315}, {120423, 16781571}, {120424, 16781827}, + {120425, 16782083}, {120426, 16782339}, {120427, 16782595}, {120428, 16782851}, + {120429, 16783107}, {120430, 16783363}, {120431, 16783619}, {120432, 16777219}, + {120433, 16777475}, {120434, 16777731}, {120435, 16777987}, {120436, 16778243}, + {120437, 16778499}, {120438, 16778755}, {120439, 16779011}, {120440, 16779267}, + {120441, 16779523}, {120442, 16779779}, {120443, 16780035}, {120444, 16780291}, + {120445, 16780547}, {120446, 16780803}, {120447, 16781059}, {120448, 16781315}, + {120449, 16781571}, {120450, 16781827}, {120451, 16782083}, {120452, 16782339}, + {120453, 16782595}, {120454, 16782851}, {120455, 16783107}, {120456, 16783363}, + {120457, 16783619}, {120458, 16777219}, {120459, 16777475}, {120460, 16777731}, + {120461, 16777987}, {120462, 16778243}, {120463, 16778499}, {120464, 16778755}, + {120465, 16779011}, {120466, 16779267}, {120467, 16779523}, {120468, 16779779}, + {120469, 16780035}, {120470, 16780291}, {120471, 16780547}, {120472, 16780803}, + {120473, 16781059}, {120474, 16781315}, {120475, 16781571}, {120476, 16781827}, + {120477, 16782083}, {120478, 16782339}, {120479, 16782595}, {120480, 16782851}, + {120481, 16783107}, {120482, 16783363}, {120483, 16783619}, {120484, 17944579}, + {120485, 17944835}, {120486, 2}, {120488, 16851715}, {120489, 16851971}, + {120490, 16852227}, {120491, 16852483}, {120492, 16852739}, {120493, 16852995}, + {120494, 16853251}, {120495, 16853507}, {120496, 16846851}, {120497, 16853763}, + {120498, 16854019}, {120499, 16786179}, {120500, 16854275}, {120501, 16854531}, + {120502, 16854787}, {120503, 16855043}, {120504, 16855299}, {120505, 16853507}, + {120506, 16855555}, {120507, 16855811}, {120508, 16856067}, {120509, 16856323}, + {120510, 16856579}, {120511, 16856835}, {120512, 16857091}, {120513, 17945091}, + {120514, 16851715}, {120515, 16851971}, {120516, 16852227}, {120517, 16852483}, + {120518, 16852739}, {120519, 16852995}, {120520, 16853251}, {120521, 16853507}, + {120522, 16846851}, {120523, 16853763}, {120524, 16854019}, {120525, 16786179}, + {120526, 16854275}, {120527, 16854531}, {120528, 16854787}, {120529, 16855043}, + {120530, 16855299}, {120531, 16855555}, {120533, 16855811}, {120534, 16856067}, + {120535, 16856323}, {120536, 16856579}, {120537, 16856835}, {120538, 16857091}, + {120539, 17945347}, {120540, 16852739}, {120541, 16853507}, {120542, 16853763}, + {120543, 16856323}, {120544, 16855299}, {120545, 16855043}, {120546, 16851715}, + {120547, 16851971}, {120548, 16852227}, {120549, 16852483}, {120550, 16852739}, + {120551, 16852995}, {120552, 16853251}, {120553, 16853507}, {120554, 16846851}, + {120555, 16853763}, {120556, 16854019}, {120557, 16786179}, {120558, 16854275}, + {120559, 16854531}, {120560, 16854787}, {120561, 16855043}, {120562, 16855299}, + {120563, 16853507}, {120564, 16855555}, {120565, 16855811}, {120566, 16856067}, + {120567, 16856323}, {120568, 16856579}, {120569, 16856835}, {120570, 16857091}, + {120571, 17945091}, {120572, 16851715}, {120573, 16851971}, {120574, 16852227}, + {120575, 16852483}, {120576, 16852739}, {120577, 16852995}, {120578, 16853251}, + {120579, 16853507}, {120580, 16846851}, {120581, 16853763}, {120582, 16854019}, + {120583, 16786179}, {120584, 16854275}, {120585, 16854531}, {120586, 16854787}, + {120587, 16855043}, {120588, 16855299}, {120589, 16855555}, {120591, 16855811}, + {120592, 16856067}, {120593, 16856323}, {120594, 16856579}, {120595, 16856835}, + {120596, 16857091}, {120597, 17945347}, {120598, 16852739}, {120599, 16853507}, + {120600, 16853763}, {120601, 16856323}, {120602, 16855299}, {120603, 16855043}, + {120604, 16851715}, {120605, 16851971}, {120606, 16852227}, {120607, 16852483}, + {120608, 16852739}, {120609, 16852995}, {120610, 16853251}, {120611, 16853507}, + {120612, 16846851}, {120613, 16853763}, {120614, 16854019}, {120615, 16786179}, + {120616, 16854275}, {120617, 16854531}, {120618, 16854787}, {120619, 16855043}, + {120620, 16855299}, {120621, 16853507}, {120622, 16855555}, {120623, 16855811}, + {120624, 16856067}, {120625, 16856323}, {120626, 16856579}, {120627, 16856835}, + {120628, 16857091}, {120629, 17945091}, {120630, 16851715}, {120631, 16851971}, + {120632, 16852227}, {120633, 16852483}, {120634, 16852739}, {120635, 16852995}, + {120636, 16853251}, {120637, 16853507}, {120638, 16846851}, {120639, 16853763}, + {120640, 16854019}, {120641, 16786179}, {120642, 16854275}, {120643, 16854531}, + {120644, 16854787}, {120645, 16855043}, {120646, 16855299}, {120647, 16855555}, + {120649, 16855811}, {120650, 16856067}, {120651, 16856323}, {120652, 16856579}, + {120653, 16856835}, {120654, 16857091}, {120655, 17945347}, {120656, 16852739}, + {120657, 16853507}, {120658, 16853763}, {120659, 16856323}, {120660, 16855299}, + {120661, 16855043}, {120662, 16851715}, {120663, 16851971}, {120664, 16852227}, + {120665, 16852483}, {120666, 16852739}, {120667, 16852995}, {120668, 16853251}, + {120669, 16853507}, {120670, 16846851}, {120671, 16853763}, {120672, 16854019}, + {120673, 16786179}, {120674, 16854275}, {120675, 16854531}, {120676, 16854787}, + {120677, 16855043}, {120678, 16855299}, {120679, 16853507}, {120680, 16855555}, + {120681, 16855811}, {120682, 16856067}, {120683, 16856323}, {120684, 16856579}, + {120685, 16856835}, {120686, 16857091}, {120687, 17945091}, {120688, 16851715}, + {120689, 16851971}, {120690, 16852227}, {120691, 16852483}, {120692, 16852739}, + {120693, 16852995}, {120694, 16853251}, {120695, 16853507}, {120696, 16846851}, + {120697, 16853763}, {120698, 16854019}, {120699, 16786179}, {120700, 16854275}, + {120701, 16854531}, {120702, 16854787}, {120703, 16855043}, {120704, 16855299}, + {120705, 16855555}, {120707, 16855811}, {120708, 16856067}, {120709, 16856323}, + {120710, 16856579}, {120711, 16856835}, {120712, 16857091}, {120713, 17945347}, + {120714, 16852739}, {120715, 16853507}, {120716, 16853763}, {120717, 16856323}, + {120718, 16855299}, {120719, 16855043}, {120720, 16851715}, {120721, 16851971}, + {120722, 16852227}, {120723, 16852483}, {120724, 16852739}, {120725, 16852995}, + {120726, 16853251}, {120727, 16853507}, {120728, 16846851}, {120729, 16853763}, + {120730, 16854019}, {120731, 16786179}, {120732, 16854275}, {120733, 16854531}, + {120734, 16854787}, {120735, 16855043}, {120736, 16855299}, {120737, 16853507}, + {120738, 16855555}, {120739, 16855811}, {120740, 16856067}, {120741, 16856323}, + {120742, 16856579}, {120743, 16856835}, {120744, 16857091}, {120745, 17945091}, + {120746, 16851715}, {120747, 16851971}, {120748, 16852227}, {120749, 16852483}, + {120750, 16852739}, {120751, 16852995}, {120752, 16853251}, {120753, 16853507}, + {120754, 16846851}, {120755, 16853763}, {120756, 16854019}, {120757, 16786179}, + {120758, 16854275}, {120759, 16854531}, {120760, 16854787}, {120761, 16855043}, + {120762, 16855299}, {120763, 16855555}, {120765, 16855811}, {120766, 16856067}, + {120767, 16856323}, {120768, 16856579}, {120769, 16856835}, {120770, 16857091}, + {120771, 17945347}, {120772, 16852739}, {120773, 16853507}, {120774, 16853763}, + {120775, 16856323}, {120776, 16855299}, {120777, 16855043}, {120778, 16858627}, + {120780, 2}, {120782, 17035267}, {120783, 16786947}, {120784, 16785155}, + {120785, 16785411}, {120786, 16787715}, {120787, 17035523}, {120788, 17035779}, + {120789, 17036035}, {120790, 17036291}, {120791, 17036547}, {120792, 17035267}, + {120793, 16786947}, {120794, 16785155}, {120795, 16785411}, {120796, 16787715}, + {120797, 17035523}, {120798, 17035779}, {120799, 17036035}, {120800, 17036291}, + {120801, 17036547}, {120802, 17035267}, {120803, 16786947}, {120804, 16785155}, + {120805, 16785411}, {120806, 16787715}, {120807, 17035523}, {120808, 17035779}, + {120809, 17036035}, {120810, 17036291}, {120811, 17036547}, {120812, 17035267}, + {120813, 16786947}, {120814, 16785155}, {120815, 16785411}, {120816, 16787715}, + {120817, 17035523}, {120818, 17035779}, {120819, 17036035}, {120820, 17036291}, + {120821, 17036547}, {120822, 17035267}, {120823, 16786947}, {120824, 16785155}, + {120825, 16785411}, {120826, 16787715}, {120827, 17035523}, {120828, 17035779}, + {120829, 17036035}, {120830, 17036291}, {120831, 17036547}, {120832, 1}, + {121484, 2}, {121499, 1}, {121504, 2}, {121505, 1}, + {121520, 2}, {122624, 1}, {122655, 2}, {122661, 1}, + {122667, 2}, {122880, 1}, {122887, 2}, {122888, 1}, + {122905, 2}, {122907, 1}, {122914, 2}, {122915, 1}, + {122917, 2}, {122918, 1}, {122923, 2}, {122928, 16866563}, + {122929, 16866819}, {122930, 16867075}, {122931, 16867331}, {122932, 16867587}, + {122933, 16867843}, {122934, 16868099}, {122935, 16868355}, {122936, 16868611}, + {122937, 16869123}, {122938, 16869379}, {122939, 16869635}, {122940, 16870147}, + {122941, 16870403}, {122942, 16870659}, {122943, 16870915}, {122944, 16871171}, + {122945, 16871427}, {122946, 16871683}, {122947, 16871939}, {122948, 16872195}, + {122949, 16872451}, {122950, 16872707}, {122951, 16873475}, {122952, 16873987}, + {122953, 16874243}, {122954, 17495043}, {122955, 16888835}, {122956, 16864003}, + {122957, 16864515}, {122958, 16890883}, {122959, 16883715}, {122960, 17945603}, + {122961, 16866563}, {122962, 16866819}, {122963, 16867075}, {122964, 16867331}, + {122965, 16867587}, {122966, 16867843}, {122967, 16868099}, {122968, 16868355}, + {122969, 16868611}, {122970, 16869123}, {122971, 16869379}, {122972, 16870147}, + {122973, 16870403}, {122974, 16870915}, {122975, 16871427}, {122976, 16871683}, + {122977, 16871939}, {122978, 16872195}, {122979, 16872451}, {122980, 16872707}, + {122981, 16873219}, {122982, 16873475}, {122983, 16879875}, {122984, 16864003}, + {122985, 16863747}, {122986, 16866307}, {122987, 16883203}, {122988, 17490179}, + {122989, 16883971}, {122990, 2}, {123023, 1}, {123024, 2}, + {123136, 1}, {123181, 2}, {123184, 1}, {123198, 2}, + {123200, 1}, {123210, 2}, {123214, 1}, {123216, 2}, + {123536, 1}, {123567, 2}, {123584, 1}, {123642, 2}, + {123647, 1}, {123648, 2}, {124112, 1}, {124154, 2}, + {124896, 1}, {124903, 2}, {124904, 1}, {124908, 2}, + {124909, 1}, {124911, 2}, {124912, 1}, {124927, 2}, + {124928, 1}, {125125, 2}, {125127, 1}, {125143, 2}, + {125184, 17945859}, {125185, 17946115}, {125186, 17946371}, {125187, 17946627}, + {125188, 17946883}, {125189, 17947139}, {125190, 17947395}, {125191, 17947651}, + {125192, 17947907}, {125193, 17948163}, {125194, 17948419}, {125195, 17948675}, + {125196, 17948931}, {125197, 17949187}, {125198, 17949443}, {125199, 17949699}, + {125200, 17949955}, {125201, 17950211}, {125202, 17950467}, {125203, 17950723}, + {125204, 17950979}, {125205, 17951235}, {125206, 17951491}, {125207, 17951747}, + {125208, 17952003}, {125209, 17952259}, {125210, 17952515}, {125211, 17952771}, + {125212, 17953027}, {125213, 17953283}, {125214, 17953539}, {125215, 17953795}, + {125216, 17954051}, {125217, 17954307}, {125218, 1}, {125260, 2}, + {125264, 1}, {125274, 2}, {125278, 1}, {125280, 2}, + {126065, 1}, {126133, 2}, {126209, 1}, {126270, 2}, + {126464, 16910339}, {126465, 17683459}, {126466, 17681667}, {126467, 17834243}, + {126468, 2}, {126469, 16910851}, {126470, 17731331}, {126471, 17682179}, + {126472, 17699843}, {126473, 16911875}, {126474, 17708547}, {126475, 17710851}, + {126476, 17682691}, {126477, 17717763}, {126478, 17694723}, {126479, 17701379}, + {126480, 17703427}, {126481, 17696771}, {126482, 17706499}, {126483, 17724931}, + {126484, 17744899}, {126485, 17686531}, {126486, 17689603}, {126487, 17684739}, + {126488, 17724419}, {126489, 17697795}, {126490, 17700867}, {126491, 17702403}, + {126492, 17954563}, {126493, 17673219}, {126494, 17954819}, {126495, 17955075}, + {126496, 2}, {126497, 17683459}, {126498, 17681667}, {126499, 2}, + {126500, 17720835}, {126501, 2}, {126503, 17682179}, {126504, 2}, + {126505, 16911875}, {126506, 17708547}, {126507, 17710851}, {126508, 17682691}, + {126509, 17717763}, {126510, 17694723}, {126511, 17701379}, {126512, 17703427}, + {126513, 17696771}, {126514, 17706499}, {126515, 2}, {126516, 17744899}, + {126517, 17686531}, {126518, 17689603}, {126519, 17684739}, {126520, 2}, + {126521, 17697795}, {126522, 2}, {126523, 17702403}, {126524, 2}, + {126530, 17681667}, {126531, 2}, {126535, 17682179}, {126536, 2}, + {126537, 16911875}, {126538, 2}, {126539, 17710851}, {126540, 2}, + {126541, 17717763}, {126542, 17694723}, {126543, 17701379}, {126544, 2}, + {126545, 17696771}, {126546, 17706499}, {126547, 2}, {126548, 17744899}, + {126549, 2}, {126551, 17684739}, {126552, 2}, {126553, 17697795}, + {126554, 2}, {126555, 17702403}, {126556, 2}, {126557, 17673219}, + {126558, 2}, {126559, 17955075}, {126560, 2}, {126561, 17683459}, + {126562, 17681667}, {126563, 2}, {126564, 17720835}, {126565, 2}, + {126567, 17682179}, {126568, 17699843}, {126569, 16911875}, {126570, 17708547}, + {126571, 2}, {126572, 17682691}, {126573, 17717763}, {126574, 17694723}, + {126575, 17701379}, {126576, 17703427}, {126577, 17696771}, {126578, 17706499}, + {126579, 2}, {126580, 17744899}, {126581, 17686531}, {126582, 17689603}, + {126583, 17684739}, {126584, 2}, {126585, 17697795}, {126586, 17700867}, + {126587, 17702403}, {126588, 17954563}, {126589, 2}, {126590, 17954819}, + {126591, 2}, {126592, 16910339}, {126593, 17683459}, {126594, 17681667}, + {126595, 17834243}, {126596, 17720835}, {126597, 16910851}, {126598, 17731331}, + {126599, 17682179}, {126600, 17699843}, {126601, 16911875}, {126602, 2}, + {126603, 17710851}, {126604, 17682691}, {126605, 17717763}, {126606, 17694723}, + {126607, 17701379}, {126608, 17703427}, {126609, 17696771}, {126610, 17706499}, + {126611, 17724931}, {126612, 17744899}, {126613, 17686531}, {126614, 17689603}, + {126615, 17684739}, {126616, 17724419}, {126617, 17697795}, {126618, 17700867}, + {126619, 17702403}, {126620, 2}, {126625, 17683459}, {126626, 17681667}, + {126627, 17834243}, {126628, 2}, {126629, 16910851}, {126630, 17731331}, + {126631, 17682179}, {126632, 17699843}, {126633, 16911875}, {126634, 2}, + {126635, 17710851}, {126636, 17682691}, {126637, 17717763}, {126638, 17694723}, + {126639, 17701379}, {126640, 17703427}, {126641, 17696771}, {126642, 17706499}, + {126643, 17724931}, {126644, 17744899}, {126645, 17686531}, {126646, 17689603}, + {126647, 17684739}, {126648, 17724419}, {126649, 17697795}, {126650, 17700867}, + {126651, 17702403}, {126652, 2}, {126704, 1}, {126706, 2}, + {126976, 1}, {127020, 2}, {127024, 1}, {127124, 2}, + {127136, 1}, {127151, 2}, {127153, 1}, {127168, 2}, + {127169, 1}, {127184, 2}, {127185, 1}, {127222, 2}, + {127233, 34732547}, {127234, 34733059}, {127235, 34733571}, {127236, 34734083}, + {127237, 34734595}, {127238, 34735107}, {127239, 34735619}, {127240, 34736131}, + {127241, 34736643}, {127242, 34737155}, {127243, 1}, {127248, 50644739}, + {127249, 50645507}, {127250, 50646275}, {127251, 50647043}, {127252, 50647811}, + {127253, 50648579}, {127254, 50649347}, {127255, 50650115}, {127256, 50650883}, + {127257, 50651651}, {127258, 50652419}, {127259, 50653187}, {127260, 50653955}, + {127261, 50654723}, {127262, 50655491}, {127263, 50656259}, {127264, 50657027}, + {127265, 50657795}, {127266, 50658563}, {127267, 50659331}, {127268, 50660099}, + {127269, 50660867}, {127270, 50661635}, {127271, 50662403}, {127272, 50663171}, + {127273, 50663939}, {127274, 51514883}, {127275, 16777731}, {127276, 16781571}, + {127277, 33554947}, {127278, 34738435}, {127279, 1}, {127280, 16777219}, + {127281, 16777475}, {127282, 16777731}, {127283, 16777987}, {127284, 16778243}, + {127285, 16778499}, {127286, 16778755}, {127287, 16779011}, {127288, 16779267}, + {127289, 16779523}, {127290, 16779779}, {127291, 16780035}, {127292, 16780291}, + {127293, 16780547}, {127294, 16780803}, {127295, 16781059}, {127296, 16781315}, + {127297, 16781571}, {127298, 16781827}, {127299, 16782083}, {127300, 16782339}, + {127301, 16782595}, {127302, 16782851}, {127303, 16783107}, {127304, 16783363}, + {127305, 16783619}, {127306, 34738947}, {127307, 34226435}, {127308, 34739459}, + {127309, 34739971}, {127310, 51517699}, {127311, 34741251}, {127312, 1}, + {127338, 34209283}, {127339, 34189315}, {127340, 34741763}, {127341, 1}, + {127376, 34742275}, {127377, 1}, {127406, 2}, {127462, 1}, + {127488, 34742787}, {127489, 34743299}, {127490, 17307651}, {127491, 2}, + {127504, 17157635}, {127505, 17966595}, {127506, 17966851}, {127507, 17351427}, + {127508, 17143043}, {127509, 17967107}, {127510, 17967363}, {127511, 17225219}, + {127512, 17967619}, {127513, 17967875}, {127514, 17968131}, {127515, 17584387}, + {127516, 17968387}, {127517, 17968643}, {127518, 17968899}, {127519, 17969155}, + {127520, 17969411}, {127521, 17969667}, {127522, 17166851}, {127523, 17969923}, + {127524, 17970179}, {127525, 17970435}, {127526, 17970691}, {127527, 17970947}, + {127528, 17971203}, {127529, 17141507}, {127530, 17223171}, {127531, 17971459}, + {127532, 17288451}, {127533, 17223939}, {127534, 17288707}, {127535, 17971715}, + {127536, 17181187}, {127537, 17971971}, {127538, 17972227}, {127539, 17972483}, + {127540, 17972739}, {127541, 17972995}, {127542, 17264131}, {127543, 17160195}, + {127544, 17973251}, {127545, 17973507}, {127546, 17973763}, {127547, 17974019}, + {127548, 2}, {127552, 51528707}, {127553, 51529475}, {127554, 51530243}, + {127555, 51531011}, {127556, 51531779}, {127557, 51532547}, {127558, 51533315}, + {127559, 51534083}, {127560, 51534851}, {127561, 2}, {127568, 17981187}, + {127569, 17981443}, {127570, 2}, {127584, 1}, {127590, 2}, + {127744, 1}, {128728, 2}, {128732, 1}, {128749, 2}, + {128752, 1}, {128765, 2}, {128768, 1}, {128887, 2}, + {128891, 1}, {128986, 2}, {128992, 1}, {129004, 2}, + {129008, 1}, {129009, 2}, {129024, 1}, {129036, 2}, + {129040, 1}, {129096, 2}, {129104, 1}, {129114, 2}, + {129120, 1}, {129160, 2}, {129168, 1}, {129198, 2}, + {129200, 1}, {129202, 2}, {129280, 1}, {129620, 2}, + {129632, 1}, {129646, 2}, {129648, 1}, {129661, 2}, + {129664, 1}, {129673, 2}, {129680, 1}, {129726, 2}, + {129727, 1}, {129734, 2}, {129742, 1}, {129756, 2}, + {129760, 1}, {129769, 2}, {129776, 1}, {129785, 2}, + {129792, 1}, {129939, 2}, {129940, 1}, {129995, 2}, + {130032, 17035267}, {130033, 16786947}, {130034, 16785155}, {130035, 16785411}, + {130036, 16787715}, {130037, 17035523}, {130038, 17035779}, {130039, 17036035}, + {130040, 17036291}, {130041, 17036547}, {130042, 2}, {131072, 1}, + {173792, 2}, {173824, 1}, {177978, 2}, {177984, 1}, + {178206, 2}, {178208, 1}, {183970, 2}, {183984, 1}, + {191457, 2}, {191472, 1}, {192094, 2}, {194560, 17981699}, + {194561, 17981955}, {194562, 17982211}, {194563, 17982467}, {194564, 17982723}, + {194565, 17608195}, {194566, 17982979}, {194567, 17983235}, {194568, 17983491}, + {194569, 17983747}, {194570, 17608451}, {194571, 17984003}, {194572, 17984259}, + {194573, 17984515}, {194574, 17608707}, {194575, 17984771}, {194576, 17985027}, + {194577, 17985283}, {194578, 17985539}, {194579, 17985795}, {194580, 17986051}, + {194581, 17968899}, {194582, 17986307}, {194583, 17986563}, {194584, 17986819}, + {194585, 17987075}, {194586, 17987331}, {194587, 17622787}, {194588, 17987587}, + {194589, 17145603}, {194590, 17987843}, {194591, 17988099}, {194592, 17988355}, + {194593, 17988611}, {194594, 17973507}, {194595, 17988867}, {194596, 17989123}, + {194597, 17624067}, {194598, 17608963}, {194599, 17609219}, {194600, 17624323}, + {194601, 17989379}, {194602, 17989635}, {194603, 17562627}, {194604, 17989891}, + {194605, 17609475}, {194606, 17990147}, {194607, 17990403}, {194608, 17990659}, + {194609, 17990915}, {194612, 17991171}, {194613, 17991427}, {194614, 17991683}, + {194615, 17991939}, {194616, 17992195}, {194617, 17992451}, {194618, 17992707}, + {194619, 17992963}, {194620, 17993219}, {194621, 17993475}, {194622, 17993731}, + {194623, 17993987}, {194624, 17994243}, {194625, 17994499}, {194626, 17994755}, + {194627, 17995011}, {194628, 17995267}, {194629, 17995523}, {194631, 17624835}, + {194632, 17995779}, {194633, 17996035}, {194634, 17996291}, {194635, 17996547}, + {194636, 17609987}, {194637, 17996803}, {194638, 17997059}, {194639, 17997315}, + {194640, 17599747}, {194641, 17997571}, {194642, 17997827}, {194643, 17998083}, + {194644, 17998339}, {194645, 17998595}, {194646, 17998851}, {194647, 17999107}, + {194648, 17999363}, {194649, 17999619}, {194650, 17999875}, {194651, 18000131}, + {194652, 18000387}, {194653, 17967107}, {194654, 18000643}, {194655, 18000899}, + {194656, 18001155}, {194657, 18001411}, {194658, 18001667}, {194659, 18001923}, + {194660, 18002179}, {194661, 18002435}, {194662, 18002691}, {194663, 18002947}, + {194664, 2}, {194665, 18003203}, {194666, 18003459}, {194668, 18003715}, + {194669, 18003971}, {194670, 18004227}, {194671, 17561603}, {194672, 18004483}, + {194673, 18004739}, {194674, 18004995}, {194675, 18005251}, {194676, 2}, + {194677, 17152259}, {194678, 18005507}, {194679, 18005763}, {194680, 17152771}, + {194681, 18006019}, {194682, 18006275}, {194683, 18006531}, {194684, 18006787}, + {194685, 18007043}, {194686, 18007299}, {194687, 18007555}, {194688, 18007811}, + {194689, 18008067}, {194690, 18008323}, {194691, 18008579}, {194692, 18008835}, + {194693, 18009091}, {194694, 18009347}, {194695, 18009603}, {194696, 18009859}, + {194697, 18010115}, {194698, 18010371}, {194699, 18010627}, {194700, 18010883}, + {194701, 18011139}, {194702, 17548291}, {194703, 18011395}, {194704, 17155331}, + {194705, 18011651}, {194707, 18011907}, {194708, 18012163}, {194710, 18012419}, + {194711, 18012675}, {194712, 18012931}, {194713, 18013187}, {194714, 18013443}, + {194715, 18013699}, {194716, 18013955}, {194717, 18014211}, {194718, 18014467}, + {194719, 18014723}, {194720, 18014979}, {194721, 18015235}, {194722, 18015491}, + {194723, 17611267}, {194724, 18015747}, {194725, 18016003}, {194726, 18016259}, + {194727, 18016515}, {194728, 17627907}, {194729, 18016515}, {194730, 18016771}, + {194731, 17611779}, {194732, 18017027}, {194733, 18017283}, {194734, 18017539}, + {194735, 18017795}, {194736, 17612035}, {194737, 17541379}, {194738, 17414659}, + {194739, 18018051}, {194740, 18018307}, {194741, 18018563}, {194742, 18018819}, + {194743, 18019075}, {194744, 18019331}, {194745, 18019587}, {194746, 18019843}, + {194747, 18020099}, {194748, 18020355}, {194749, 18020611}, {194750, 18020867}, + {194751, 18021123}, {194752, 18021379}, {194753, 18021635}, {194754, 18021891}, + {194755, 18022147}, {194756, 18022403}, {194757, 18022659}, {194758, 18022915}, + {194759, 18023171}, {194760, 17612291}, {194761, 18023427}, {194762, 18023683}, + {194763, 18023939}, {194764, 18024195}, {194765, 18024451}, {194766, 18024707}, + {194767, 17612803}, {194768, 18024963}, {194769, 18025219}, {194770, 18025475}, + {194771, 18025731}, {194772, 18025987}, {194773, 18026243}, {194774, 18026499}, + {194775, 18026755}, {194776, 17548547}, {194777, 17629955}, {194778, 18027011}, + {194779, 18027267}, {194780, 18027523}, {194781, 18027779}, {194782, 18028035}, + {194783, 18028291}, {194784, 18028547}, {194785, 18028803}, {194786, 17613059}, + {194787, 18029059}, {194788, 18029315}, {194789, 18029571}, {194790, 18029827}, + {194791, 17640707}, {194792, 18030083}, {194793, 18030339}, {194794, 18030595}, + {194795, 18030851}, {194796, 18031107}, {194797, 18031363}, {194798, 18031619}, + {194799, 18031875}, {194800, 18032131}, {194801, 18032387}, {194802, 18032643}, + {194803, 18032899}, {194804, 18033155}, {194805, 17565955}, {194806, 18033411}, + {194807, 18033667}, {194808, 18033923}, {194809, 18034179}, {194810, 18034435}, + {194811, 18034691}, {194812, 18034947}, {194813, 18035203}, {194814, 18035459}, + {194815, 18035715}, {194816, 18035971}, {194817, 17613315}, {194818, 17586947}, + {194819, 18036227}, {194820, 18036483}, {194821, 18036739}, {194822, 18036995}, + {194823, 18037251}, {194824, 18037507}, {194825, 18037763}, {194826, 18038019}, + {194827, 17630723}, {194828, 18038275}, {194829, 18038531}, {194830, 18038787}, + {194831, 18039043}, {194832, 18039299}, {194833, 18039555}, {194834, 18039811}, + {194835, 18040067}, {194836, 17630979}, {194837, 18040323}, {194838, 18040579}, + {194839, 18040835}, {194840, 18041091}, {194841, 18041347}, {194842, 18041603}, + {194843, 18041859}, {194844, 18042115}, {194845, 18042371}, {194846, 18042627}, + {194847, 2}, {194848, 18042883}, {194849, 17631491}, {194850, 18043139}, + {194851, 18043395}, {194852, 18043651}, {194853, 18043907}, {194854, 18044163}, + {194855, 18044419}, {194856, 18044675}, {194857, 18044931}, {194858, 18045187}, + {194859, 18045443}, {194860, 18045699}, {194862, 18045955}, {194863, 18046211}, + {194864, 17632003}, {194865, 18046467}, {194866, 18046723}, {194867, 18046979}, + {194868, 18047235}, {194869, 18047491}, {194870, 18047747}, {194871, 18048003}, + {194872, 17562371}, {194873, 18048259}, {194874, 18048515}, {194875, 18048771}, + {194876, 18049027}, {194877, 18049283}, {194878, 18049539}, {194879, 18049795}, + {194880, 17633539}, {194881, 18050051}, {194882, 18050307}, {194883, 18050563}, + {194884, 18050819}, {194885, 18051075}, {194886, 18051331}, {194888, 17633795}, + {194889, 17641219}, {194890, 18051587}, {194891, 18051843}, {194892, 18052099}, + {194893, 18052355}, {194894, 18052611}, {194895, 17552899}, {194896, 17634307}, + {194897, 18052867}, {194898, 18053123}, {194899, 17615875}, {194900, 18053379}, + {194901, 18053635}, {194902, 17604867}, {194903, 18053891}, {194904, 18054147}, + {194905, 17616643}, {194906, 18054403}, {194907, 18054659}, {194908, 18054915}, + {194909, 18055171}, {194911, 2}, {194912, 18055427}, {194913, 18055683}, + {194914, 18055939}, {194915, 18056195}, {194916, 18056451}, {194917, 18056707}, + {194918, 18056963}, {194919, 18057219}, {194920, 18057475}, {194921, 18057731}, + {194922, 18057987}, {194923, 18058243}, {194924, 18058499}, {194925, 18058755}, + {194926, 18059011}, {194927, 18059267}, {194928, 18059523}, {194929, 18059779}, + {194930, 18060035}, {194931, 18060291}, {194932, 18060547}, {194933, 18060803}, + {194934, 18061059}, {194935, 18061315}, {194936, 18061571}, {194937, 18061827}, + {194938, 17618179}, {194939, 18062083}, {194940, 18062339}, {194941, 18062595}, + {194942, 18062851}, {194943, 18063107}, {194944, 18063363}, {194945, 18063619}, + {194946, 18063875}, {194947, 18064131}, {194948, 18064387}, {194949, 18064643}, + {194950, 18064899}, {194951, 18065155}, {194952, 18065411}, {194953, 18065667}, + {194954, 18065923}, {194955, 18011907}, {194956, 18066179}, {194957, 18066435}, + {194958, 18066691}, {194959, 18066947}, {194960, 18067203}, {194961, 18067459}, + {194962, 18067715}, {194963, 18067971}, {194964, 18068227}, {194965, 18068483}, + {194966, 18068739}, {194967, 18068995}, {194968, 17566723}, {194969, 18069251}, + {194970, 18069507}, {194971, 18069763}, {194972, 18070019}, {194973, 18070275}, + {194974, 18070531}, {194975, 17618947}, {194976, 18070787}, {194977, 18071043}, + {194978, 18071299}, {194979, 18071555}, {194980, 18071811}, {194981, 18072067}, + {194982, 18072323}, {194983, 18072579}, {194984, 18072835}, {194985, 18073091}, + {194986, 18073347}, {194987, 18073603}, {194988, 18073859}, {194989, 18074115}, + {194990, 18074371}, {194991, 18074627}, {194992, 18074883}, {194993, 18075139}, + {194994, 18075395}, {194995, 18075651}, {194996, 17551619}, {194997, 18075907}, + {194998, 18076163}, {194999, 18076419}, {195000, 18076675}, {195001, 18076931}, + {195002, 18077187}, {195003, 17636099}, {195004, 18077443}, {195005, 18077699}, + {195006, 18077955}, {195007, 2}, {195008, 18078211}, {195009, 18078467}, + {195010, 18078723}, {195011, 18078979}, {195012, 17178371}, {195013, 18079235}, + {195014, 18079491}, {195015, 18079747}, {195016, 18080003}, {195017, 18080259}, + {195018, 18080515}, {195019, 18080771}, {195020, 18081027}, {195021, 18081283}, + {195022, 18081539}, {195023, 18081795}, {195024, 17637379}, {195025, 17637635}, + {195026, 17180163}, {195027, 18082051}, {195028, 18082307}, {195029, 18082563}, + {195030, 18082819}, {195031, 18083075}, {195032, 18083331}, {195033, 18083587}, + {195034, 18083843}, {195035, 18084099}, {195036, 18084355}, {195037, 18084611}, + {195038, 18084867}, {195039, 17637891}, {195040, 18085123}, {195041, 18085379}, + {195042, 18085635}, {195043, 18085891}, {195044, 18086147}, {195045, 18086403}, + {195046, 18086659}, {195047, 18086915}, {195048, 18087171}, {195049, 18087427}, + {195050, 18087683}, {195051, 18087939}, {195052, 18088195}, {195053, 18088451}, + {195054, 18088707}, {195055, 18088963}, {195056, 18089219}, {195057, 18089475}, + {195058, 18089731}, {195059, 18089987}, {195060, 18090243}, {195061, 18090499}, + {195062, 18090755}, {195063, 18091011}, {195064, 18091267}, {195065, 18091523}, + {195066, 18091779}, {195067, 18092035}, {195068, 18092291}, {195069, 18092547}, + {195070, 17639427}, {195072, 18092803}, {195073, 18093059}, {195074, 18093315}, + {195075, 18093571}, {195076, 18093827}, {195077, 18094083}, {195078, 18094339}, + {195079, 18094595}, {195080, 18094851}, {195081, 18095107}, {195082, 17639683}, + {195083, 18095363}, {195084, 18095619}, {195085, 18095875}, {195086, 18096131}, + {195087, 18096387}, {195088, 18096643}, {195089, 18096899}, {195090, 18097155}, + {195091, 18097411}, {195092, 18097667}, {195093, 17192451}, {195094, 18097923}, + {195095, 17193475}, {195096, 18098179}, {195097, 18098435}, {195098, 18098691}, + {195099, 18098947}, {195100, 17194755}, {195101, 18099203}, {195102, 2}, + {196608, 1}, {201547, 2}, {201552, 1}, {205744, 2}, + {917760, 0}, {918000, 2} +}; + + +} // namespace ada::idna +#endif // ADA_IDNA_TABLES_H +/* end file src/mapping_tables.cpp */ + +namespace ada::idna { + +// This can be greatly accelerated. For now we just use a simply +// binary search. In practice, you should *not* do that. +uint32_t find_range_index(uint32_t key) { + //////////////// + // This could be implemented with std::lower_bound, but we roll our own + // because we want to allow further optimizations in the future. + //////////////// + uint32_t len = std::size(table); + uint32_t low = 0; + uint32_t high = len - 1; + while (low <= high) { + uint32_t middle_index = (low + high) >> 1; // cannot overflow + uint32_t middle_value = table[middle_index][0]; + if (middle_value < key) { + low = middle_index + 1; + } else if (middle_value > key) { + high = middle_index - 1; + } else { + return middle_index; // perfect match + } + } + return low == 0 ? 0 : low - 1; +} + +bool ascii_has_upper_case(char* input, size_t length) { + auto broadcast = [](uint8_t v) -> uint64_t { + return 0x101010101010101ull * v; + }; + uint64_t broadcast_80 = broadcast(0x80); + uint64_t broadcast_Ap = broadcast(128 - 'A'); + uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1); + size_t i = 0; + + uint64_t runner{0}; + + for (; i + 7 < length; i += 8) { + uint64_t word{}; + memcpy(&word, input + i, sizeof(word)); + runner |= (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80); + } + if (i < length) { + uint64_t word{}; + memcpy(&word, input + i, length - i); + runner |= (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80); + } + return runner != 0; +} + +void ascii_map(char* input, size_t length) { + auto broadcast = [](uint8_t v) -> uint64_t { + return 0x101010101010101ull * v; + }; + uint64_t broadcast_80 = broadcast(0x80); + uint64_t broadcast_Ap = broadcast(128 - 'A'); + uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1); + size_t i = 0; + + for (; i + 7 < length; i += 8) { + uint64_t word{}; + memcpy(&word, input + i, sizeof(word)); + word ^= + (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; + memcpy(input + i, &word, sizeof(word)); + } + if (i < length) { + uint64_t word{}; + memcpy(&word, input + i, length - i); + word ^= + (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; + memcpy(input + i, &word, length - i); + } +} + +// Map the characters according to IDNA, returning the empty string on error. +std::u32string map(std::u32string_view input) { + // [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap). + // For each code point in the domain_name string, look up the status + // value in Section 5, [IDNA Mapping + // Table](https://www.unicode.org/reports/tr46/#IDNA_Mapping_Table), + // and take the following actions: + // * disallowed: Leave the code point unchanged in the string, and + // record that there was an error. + // * ignored: Remove the code point from the string. This is + // equivalent to mapping the code point to an empty string. + // * mapped: Replace the code point in the string by the value for + // the mapping in Section 5, [IDNA Mapping + // Table](https://www.unicode.org/reports/tr46/#IDNA_Mapping_Table). + // * valid: Leave the code point unchanged in the string. + static std::u32string error = U""; + std::u32string answer; + answer.reserve(input.size()); + for (char32_t x : input) { + size_t index = find_range_index(x); + uint32_t descriptor = table[index][1]; + uint8_t code = uint8_t(descriptor); + switch (code) { + case 0: + break; // nothing to do, ignored + case 1: + answer.push_back(x); // valid, we just copy it to output + break; + case 2: + return error; // disallowed + // case 3 : + default: + // We have a mapping + { + size_t char_count = (descriptor >> 24); + uint16_t char_index = uint16_t(descriptor >> 8); + for (size_t idx = char_index; idx < char_index + char_count; idx++) { + answer.push_back(mappings[idx]); + } + } + } + } + return answer; +} +} // namespace ada::idna +/* end file src/mapping.cpp */ +/* begin file src/normalization.cpp */ +/* begin file src/normalization_tables.cpp */ +// IDNA 15.0.0 + +// clang-format off +#ifndef ADA_IDNA_NORMALIZATION_TABLES_H +#define ADA_IDNA_NORMALIZATION_TABLES_H +#include + +/** + * Unicode Standard Annex #15 + * + * UNICODE NORMALIZATION FORMS + * https://www.unicode.org/reports/tr15/ + * + * See https://github.com/uni-algo/uni-algo/blob/c612968c5ed3ace39bde4c894c24286c5f2c7fe2/include/uni_algo/impl/data/data_norm.h for reference. + */ + +namespace ada::idna { + +const uint8_t decomposition_index[4352] = { + 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 16, 7, 17, 18, 19, 20, 21, 22, 23, 24, 7, + 7, 7, 7, 7, 25, 7, 26, 27, 28, 29, 30, 31, 32, 33, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 34, 35, 7, 7, 7, + 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 37, 38, 39, 40, 41, 42, 43, 7, 7, 7, 7, 7, 7, 7, 44, 7, 7, + 7, 7, 7, 7, 7, 7, 45, 46, 7, 47, 48, 49, 7, 7, 7, 50, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 51, 7, 52, 53, 54, 55, 56, 7, 7, 7, + 7, 7, 7, 7, 7, 57, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 58, + 59, 7, 60, 61, 62, 7, 7, 7, 7, 7, 7, 7, 7, 63, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 64, 65, 66, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7}; + +const uint16_t decomposition_block[67][257] = { + {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 8, 8, 8, 8, + 8, 8, 8, 9, 16, 17, 20, 20, 20, 20, 21, 28, 28, 29, 33, + 37, 45, 48, 48, 49, 57, 61, 64, 65, 77, 89, 100, 100, 108, 116, + 124, 132, 140, 148, 148, 156, 164, 172, 180, 188, 196, 204, 212, 220, 220, + 228, 236, 244, 252, 260, 268, 268, 268, 276, 284, 292, 300, 308, 308, 308, + 316, 324, 332, 340, 348, 356, 356, 364, 372, 380, 388, 396, 404, 412, 420, + 428, 428, 436, 444, 452, 460, 468, 476, 476, 476, 484, 492, 500, 508, 516, + 516, 524}, + {524, 532, 540, 548, 556, 564, 572, 580, 588, 596, 604, 612, + 620, 628, 636, 644, 652, 652, 652, 660, 668, 676, 684, 692, + 700, 708, 716, 724, 732, 740, 748, 756, 764, 772, 780, 788, + 796, 804, 812, 812, 812, 820, 828, 836, 844, 852, 860, 868, + 876, 884, 885, 893, 900, 908, 916, 924, 932, 932, 940, 948, + 956, 964, 972, 981, 989, 996, 996, 996, 1004, 1012, 1020, 1028, + 1036, 1045, 1052, 1052, 1052, 1060, 1068, 1076, 1084, 1092, 1100, 1100, + 1100, 1108, 1116, 1124, 1132, 1140, 1148, 1156, 1164, 1172, 1180, 1188, + 1196, 1204, 1212, 1220, 1228, 1236, 1244, 1244, 1244, 1252, 1260, 1268, + 1276, 1284, 1292, 1300, 1308, 1316, 1324, 1332, 1340, 1348, 1356, 1364, + 1372, 1380, 1388, 1396, 1404, 1412, 1420, 1429, 1432, 1432, 1432, 1432, + 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, + 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, + 1432, 1432, 1432, 1432, 1432, 1440, 1448, 1448, 1448, 1448, 1448, 1448, + 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1456, 1464, 1464, 1464, + 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, + 1464, 1464, 1464, 1464, 1465, 1477, 1489, 1501, 1509, 1517, 1525, 1533, + 1541, 1548, 1556, 1564, 1572, 1580, 1588, 1596, 1604, 1612, 1624, 1636, + 1648, 1660, 1672, 1684, 1696, 1708, 1708, 1720, 1732, 1744, 1756, 1764, + 1772, 1772, 1772, 1780, 1788, 1796, 1804, 1812, 1820, 1832, 1844, 1852, + 1860, 1869, 1877, 1885, 1892, 1900, 1908, 1908, 1908, 1916, 1924, 1936, + 1948, 1956, 1964, 1972, 1980}, + {1980, 1988, 1996, 2004, 2012, 2020, 2028, 2036, 2044, 2052, 2060, 2068, + 2076, 2084, 2092, 2100, 2108, 2116, 2124, 2132, 2140, 2148, 2156, 2164, + 2172, 2180, 2188, 2196, 2204, 2204, 2204, 2212, 2220, 2220, 2220, 2220, + 2220, 2220, 2220, 2228, 2236, 2244, 2252, 2264, 2276, 2288, 2300, 2308, + 2316, 2328, 2340, 2348, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, + 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2357, 2361, 2365, 2369, + 2373, 2377, 2381, 2385, 2389, 2392, 2392, 2392, 2392, 2392, 2392, 2392, + 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, + 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392, + 2393, 2401, 2409, 2417, 2425, 2433, 2440, 2440, 2441, 2445, 2449, 2453, + 2457, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, + 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, + 2460, 2460, 2460, 2460, 2460}, + {2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, + 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, + 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, + 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, + 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460, + 2460, 2460, 2460, 2460, 2460, 2464, 2468, 2468, 2472, 2480, 2480, 2480, + 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, + 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, + 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, + 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2480, 2484, 2484, 2484, + 2484, 2484, 2485, 2492, 2492, 2492, 2492, 2496, 2496, 2496, 2496, 2496, + 2497, 2506, 2512, 2520, 2524, 2532, 2540, 2548, 2548, 2556, 2556, 2564, + 2572, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, + 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, 2584, + 2584, 2584, 2584, 2592, 2600, 2608, 2616, 2624, 2632, 2644, 2644, 2644, + 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, + 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2644, 2652, + 2660, 2668, 2676, 2684, 2685, 2689, 2693, 2698, 2706, 2713, 2717, 2720, + 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, + 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, 2720, + 2721, 2725, 2729, 2732, 2733, 2737, 2740, 2740, 2740, 2741, 2744, 2744, + 2744, 2744, 2744, 2744, 2744}, + {2744, 2752, 2760, 2760, 2768, 2768, 2768, 2768, 2776, 2776, 2776, 2776, + 2776, 2784, 2792, 2800, 2800, 2800, 2800, 2800, 2800, 2800, 2800, 2800, + 2800, 2800, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, + 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, + 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2808, 2816, 2816, + 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, + 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2816, 2824, 2832, 2832, + 2840, 2840, 2840, 2840, 2848, 2848, 2848, 2848, 2848, 2856, 2864, 2872, + 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, + 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2872, 2880, + 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, + 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, + 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, + 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, + 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, + 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888, + 2888, 2888, 2896, 2904, 2904, 2904, 2904, 2904, 2904, 2904, 2904, 2904, + 2904, 2904, 2904, 2904, 2904, 2912, 2920, 2928, 2936, 2936, 2936, 2944, + 2952, 2952, 2952, 2960, 2968, 2976, 2984, 2992, 3000, 3000, 3000, 3008, + 3016, 3024, 3032, 3040, 3048, 3048, 3048, 3056, 3064, 3072, 3080, 3088, + 3096, 3104, 3112, 3120, 3128, 3136, 3144, 3144, 3144, 3152, 3160, 3160, + 3160, 3160, 3160, 3160, 3160}, + {3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160, + 3160, 3160, 3160, 3161, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168}, + {3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, + 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3168, 3176, + 3184, 3192, 3200, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, + 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, + 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, + 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, + 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, + 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, + 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3208, 3209, 3217, 3225, + 3233, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, + 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, + 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, + 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, + 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, + 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, + 3240, 3248, 3248, 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3256, + 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3264, 3264, 3264, 3264, + 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, + 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, + 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, + 3264, 3264, 3264, 3264, 3264}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, + 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, + 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, + 3264, 3264, 3264, 3264, 3264, 3264, 3272, 3272, 3272, 3272, 3272, 3272, + 3272, 3272, 3280, 3280, 3280, 3288, 3288, 3288, 3288, 3288, 3288, 3288, + 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, + 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288, + 3288, 3288, 3288, 3288, 3288, 3296, 3304, 3312, 3320, 3328, 3336, 3344, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, 3352, + 3360, 3368, 3368, 3368, 3368, 3368, 3368, 3368, 3368, 3368, 3368, 3368, + 3368, 3368, 3368, 3368, 3368, 3376, 3384, 3384, 3392, 3392, 3392, 3392, + 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, + 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, + 3392, 3392, 3392, 3392, 3392}, + {3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, + 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, + 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, + 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, + 3392, 3392, 3392, 3392, 3400, 3400, 3400, 3408, 3408, 3408, 3408, 3408, + 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, + 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, + 3408, 3408, 3408, 3408, 3408, 3408, 3416, 3424, 3432, 3432, 3432, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440}, + {3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3448, 3448, 3448, 3456, 3464, 3464, 3464, 3464, 3464, 3464, 3464, + 3464, 3464, 3464, 3464, 3464, 3464, 3464, 3464, 3464, 3472, 3480, 3480, + 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, + 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, + 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, + 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, 3480, + 3480, 3480, 3480, 3480, 3480, 3488, 3488, 3488, 3488, 3488, 3488, 3488, + 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, + 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, + 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, + 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3488, 3496, + 3504, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512}, + {3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, 3512, + 3512, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, 3520, + 3520, 3528, 3528, 3528, 3528, 3528, 3528, 3528, 3536, 3544, 3544, 3552, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564}, + {3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, 3564, + 3564, 3564, 3564, 3572, 3580, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, 3588, + 3588, 3588, 3588, 3596, 3596, 3604, 3616, 3624, 3624, 3624, 3624, 3624, + 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, + 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, + 3624, 3624, 3624, 3624, 3624}, + {3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, + 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, + 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, + 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, 3624, + 3624, 3624, 3624, 3625, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, + 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3632, 3633, + 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, + 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, + 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, 3640, + 3640, 3640, 3640, 3640, 3641, 3649, 3656, 3656, 3656, 3656, 3656, 3656, + 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, + 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, + 3656, 3656, 3656, 3656, 3656}, + {3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, 3656, + 3657, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, + 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, + 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, + 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, + 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3660, 3668, 3668, 3668, 3668, + 3668, 3668, 3668, 3668, 3668, 3668, 3676, 3676, 3676, 3676, 3676, 3684, + 3684, 3684, 3684, 3684, 3692, 3692, 3692, 3692, 3692, 3700, 3700, 3700, + 3700, 3700, 3700, 3700, 3700, 3700, 3700, 3700, 3700, 3700, 3708, 3708, + 3708, 3708, 3708, 3708, 3708, 3708, 3708, 3708, 3716, 3716, 3724, 3733, + 3744, 3753, 3764, 3764, 3764, 3764, 3764, 3764, 3764, 3764, 3772, 3772, + 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, 3772, + 3772, 3772, 3772, 3772, 3780, 3780, 3780, 3780, 3780, 3780, 3780, 3780, + 3780, 3780, 3788, 3788, 3788, 3788, 3788, 3796, 3796, 3796, 3796, 3796, + 3804, 3804, 3804, 3804, 3804, 3812, 3812, 3812, 3812, 3812, 3812, 3812, + 3812, 3812, 3812, 3812, 3812, 3812, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3820, 3820}, + {3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, 3820, + 3820, 3820, 3820, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, 3828, + 3829, 3832, 3832, 3832, 3832}, + {3832, 3832, 3832, 3832, 3832, 3832, 3832, 3840, 3840, 3848, 3848, 3856, + 3856, 3864, 3864, 3872, 3872, 3872, 3872, 3880, 3880, 3880, 3880, 3880, + 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, + 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, + 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, 3880, + 3888, 3888, 3896, 3896, 3896, 3904, 3912, 3912, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920}, + {3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, + 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3920, 3921, 3925, 3929, 3932, + 3933, 3937, 3941, 3945, 3949, 3953, 3957, 3961, 3965, 3969, 3973, 3976, + 3977, 3981, 3985, 3989, 3993, 3997, 4001, 4005, 4009, 4013, 4017, 4021, + 4025, 4029, 4033, 4037, 4041, 4045, 4048, 4049, 4053, 4057, 4061, 4065, + 4069, 4073, 4077, 4081, 4085, 4089, 4093, 4097, 4101, 4105, 4109, 4113, + 4117, 4121, 4125, 4129, 4133, 4137, 4141, 4145, 4149, 4153, 4157, 4160, + 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, 4160, + 4161, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, + 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, + 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4164, 4165, + 4169, 4173, 4177, 4181, 4185, 4189, 4193, 4197, 4201, 4205, 4209, 4213, + 4217, 4221, 4225, 4229, 4233, 4237, 4241, 4245, 4249, 4253, 4257, 4261, + 4265, 4269, 4273, 4277, 4281, 4285, 4289, 4293, 4297, 4301, 4305, 4309, + 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, + 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, + 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, + 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, + 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, 4312, + 4312, 4312, 4312, 4312, 4312}, + {4312, 4320, 4328, 4336, 4344, 4352, 4360, 4368, 4376, 4388, 4400, 4408, + 4416, 4424, 4432, 4440, 4448, 4456, 4464, 4472, 4480, 4492, 4504, 4516, + 4528, 4536, 4544, 4552, 4560, 4572, 4584, 4592, 4600, 4608, 4616, 4624, + 4632, 4640, 4648, 4656, 4664, 4672, 4680, 4688, 4696, 4704, 4712, 4724, + 4736, 4744, 4752, 4760, 4768, 4776, 4784, 4792, 4800, 4812, 4824, 4832, + 4840, 4848, 4856, 4864, 4872, 4880, 4888, 4896, 4904, 4912, 4920, 4928, + 4936, 4944, 4952, 4960, 4968, 4980, 4992, 5004, 5016, 5028, 5040, 5052, + 5064, 5072, 5080, 5088, 5096, 5104, 5112, 5120, 5128, 5140, 5152, 5160, + 5168, 5176, 5184, 5192, 5200, 5212, 5224, 5236, 5248, 5260, 5272, 5280, + 5288, 5296, 5304, 5312, 5320, 5328, 5336, 5344, 5352, 5360, 5368, 5376, + 5384, 5396, 5408, 5420, 5432, 5440, 5448, 5456, 5464, 5472, 5480, 5488, + 5496, 5504, 5512, 5520, 5528, 5536, 5544, 5552, 5560, 5568, 5576, 5584, + 5592, 5600, 5608, 5616, 5624, 5632, 5640, 5648, 5656, 5664, 5673, 5682, + 5688, 5688, 5688, 5688, 5688, 5696, 5704, 5712, 5720, 5732, 5744, 5756, + 5768, 5780, 5792, 5804, 5816, 5828, 5840, 5852, 5864, 5876, 5888, 5900, + 5912, 5924, 5936, 5948, 5960, 5968, 5976, 5984, 5992, 6000, 6008, 6020, + 6032, 6044, 6056, 6068, 6080, 6092, 6104, 6116, 6128, 6136, 6144, 6152, + 6160, 6168, 6176, 6184, 6192, 6204, 6216, 6228, 6240, 6252, 6264, 6276, + 6288, 6300, 6312, 6324, 6336, 6348, 6360, 6372, 6384, 6396, 6408, 6420, + 6432, 6440, 6448, 6456, 6464, 6476, 6488, 6500, 6512, 6524, 6536, 6548, + 6560, 6572, 6584, 6592, 6600, 6608, 6616, 6624, 6632, 6640, 6648, 6648, + 6648, 6648, 6648, 6648, 6648}, + {6648, 6656, 6664, 6676, 6688, 6700, 6712, 6724, 6736, 6744, 6752, 6764, + 6776, 6788, 6800, 6812, 6824, 6832, 6840, 6852, 6864, 6876, 6888, 6888, + 6888, 6896, 6904, 6916, 6928, 6940, 6952, 6952, 6952, 6960, 6968, 6980, + 6992, 7004, 7016, 7028, 7040, 7048, 7056, 7068, 7080, 7092, 7104, 7116, + 7128, 7136, 7144, 7156, 7168, 7180, 7192, 7204, 7216, 7224, 7232, 7244, + 7256, 7268, 7280, 7292, 7304, 7312, 7320, 7332, 7344, 7356, 7368, 7368, + 7368, 7376, 7384, 7396, 7408, 7420, 7432, 7432, 7432, 7440, 7448, 7460, + 7472, 7484, 7496, 7508, 7520, 7520, 7528, 7528, 7540, 7540, 7552, 7552, + 7564, 7572, 7580, 7592, 7604, 7616, 7628, 7640, 7652, 7660, 7668, 7680, + 7692, 7704, 7716, 7728, 7740, 7748, 7756, 7764, 7772, 7780, 7788, 7796, + 7804, 7812, 7820, 7828, 7836, 7844, 7852, 7852, 7852, 7864, 7876, 7892, + 7908, 7924, 7940, 7956, 7972, 7984, 7996, 8012, 8028, 8044, 8060, 8076, + 8092, 8104, 8116, 8132, 8148, 8164, 8180, 8196, 8212, 8224, 8236, 8252, + 8268, 8284, 8300, 8316, 8332, 8344, 8356, 8372, 8388, 8404, 8420, 8436, + 8452, 8464, 8476, 8492, 8508, 8524, 8540, 8556, 8572, 8580, 8588, 8600, + 8608, 8620, 8620, 8628, 8640, 8648, 8656, 8664, 8672, 8681, 8688, 8693, + 8701, 8710, 8716, 8728, 8736, 8748, 8748, 8756, 8768, 8776, 8784, 8792, + 8800, 8810, 8818, 8826, 8832, 8840, 8848, 8860, 8872, 8872, 8872, 8880, + 8892, 8900, 8908, 8916, 8924, 8926, 8934, 8942, 8948, 8956, 8964, 8976, + 8988, 8996, 9004, 9012, 9024, 9032, 9040, 9048, 9056, 9066, 9074, 9080, + 9084, 9084, 9084, 9096, 9104, 9116, 9116, 9124, 9136, 9144, 9152, 9160, + 9168, 9178, 9181, 9188, 9190}, + {9190, 9194, 9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, 9229, 9232, + 9232, 9232, 9232, 9232, 9232, 9233, 9236, 9236, 9236, 9236, 9236, 9237, + 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, 9244, + 9245, 9249, 9257, 9268, 9268, 9268, 9268, 9268, 9268, 9268, 9268, 9269, + 9272, 9272, 9272, 9273, 9281, 9292, 9293, 9301, 9312, 9312, 9312, 9312, + 9313, 9320, 9321, 9328, 9328, 9328, 9328, 9328, 9328, 9328, 9328, 9329, + 9337, 9345, 9352, 9352, 9352, 9352, 9352, 9352, 9352, 9352, 9352, 9352, + 9352, 9352, 9352, 9353, 9368, 9368, 9368, 9368, 9368, 9368, 9368, 9369, + 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, 9372, + 9372, 9372, 9372, 9372, 9373, 9377, 9380, 9380, 9381, 9385, 9389, 9393, + 9397, 9401, 9405, 9409, 9413, 9417, 9421, 9425, 9429, 9433, 9437, 9441, + 9445, 9449, 9453, 9457, 9461, 9465, 9469, 9473, 9477, 9481, 9485, 9488, + 9489, 9493, 9497, 9501, 9505, 9509, 9513, 9517, 9521, 9525, 9529, 9533, + 9537, 9540, 9540, 9540, 9540, 9540, 9540, 9540, 9540, 9540, 9540, 9540, + 9541, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, + 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, + 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, + 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, + 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, + 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, + 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, 9548, + 9548, 9548, 9548, 9548, 9549}, + {9549, 9561, 9573, 9577, 9584, 9585, 9597, 9609, 9612, 9613, + 9621, 9625, 9629, 9633, 9637, 9641, 9645, 9649, 9653, 9657, + 9660, 9661, 9665, 9672, 9672, 9673, 9677, 9681, 9685, 9689, + 9692, 9692, 9693, 9701, 9713, 9720, 9721, 9724, 9724, 9728, + 9729, 9732, 9732, 9736, 9745, 9749, 9752, 9753, 9757, 9761, + 9764, 9765, 9769, 9773, 9777, 9781, 9785, 9789, 9792, 9793, + 9805, 9809, 9813, 9817, 9821, 9824, 9824, 9824, 9824, 9825, + 9829, 9833, 9837, 9841, 9844, 9844, 9844, 9844, 9844, 9844, + 9845, 9857, 9869, 9885, 9897, 9909, 9921, 9933, 9945, 9957, + 9969, 9981, 9993, 10005, 10017, 10029, 10037, 10041, 10049, 10061, + 10069, 10073, 10081, 10093, 10109, 10117, 10121, 10129, 10141, 10145, + 10149, 10153, 10157, 10161, 10169, 10181, 10189, 10193, 10201, 10213, + 10229, 10237, 10241, 10249, 10261, 10265, 10269, 10273, 10276, 10276, + 10276, 10276, 10276, 10276, 10276, 10276, 10276, 10277, 10288, 10288, + 10288, 10288, 10288, 10288, 10288, 10288, 10288, 10288, 10288, 10288, + 10288, 10288, 10288, 10288, 10288, 10296, 10304, 10304, 10304, 10304, + 10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304, + 10304, 10304, 10304, 10304, 10304, 10312, 10312, 10312, 10312, 10312, + 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, + 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, 10312, + 10312, 10312, 10312, 10312, 10312, 10312, 10320, 10328, 10336, 10336, + 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, + 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, + 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, + 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, 10336, + 10336, 10336, 10336, 10336, 10336, 10336, 10336}, + {10336, 10336, 10336, 10336, 10336, 10344, 10344, 10344, 10344, 10344, + 10352, 10352, 10352, 10360, 10360, 10360, 10360, 10360, 10360, 10360, + 10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360, + 10360, 10360, 10360, 10360, 10360, 10360, 10360, 10368, 10368, 10376, + 10376, 10376, 10376, 10376, 10377, 10385, 10396, 10397, 10405, 10416, + 10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416, + 10416, 10416, 10416, 10416, 10416, 10416, 10424, 10424, 10424, 10432, + 10432, 10432, 10440, 10440, 10448, 10448, 10448, 10448, 10448, 10448, + 10448, 10448, 10448, 10448, 10448, 10448, 10448, 10448, 10448, 10448, + 10448, 10448, 10448, 10448, 10448, 10448, 10448, 10456, 10456, 10464, + 10464, 10464, 10464, 10464, 10464, 10464, 10464, 10464, 10464, 10464, + 10472, 10480, 10488, 10496, 10504, 10504, 10504, 10512, 10520, 10520, + 10520, 10528, 10536, 10536, 10536, 10536, 10536, 10536, 10536, 10544, + 10552, 10552, 10552, 10560, 10568, 10568, 10568, 10576, 10584, 10584, + 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, + 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, + 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, 10584, + 10584, 10584, 10584, 10592, 10600, 10608, 10616, 10616, 10616, 10616, + 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, + 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, + 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, + 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, 10616, + 10616, 10616, 10616, 10616, 10616, 10624, 10632, 10640, 10648, 10648, + 10648, 10648, 10648, 10648, 10648, 10656, 10664, 10672, 10680, 10680, + 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, + 10680, 10680, 10680, 10680, 10680, 10680, 10680}, + {10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, + 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, + 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, + 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, 10680, + 10680, 10680, 10684, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688}, + {10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, 10688, + 10688, 10688, 10688, 10688, 10688, 10688, 10689, 10693, 10697, 10701, + 10705, 10709, 10713, 10717, 10721, 10725, 10733, 10741, 10749, 10757, + 10765, 10773, 10781, 10789, 10797, 10805, 10813, 10825, 10837, 10849, + 10861, 10873, 10885, 10897, 10909, 10921, 10937, 10953, 10969, 10985, + 11001, 11017, 11033, 11049, 11065, 11081, 11097, 11105, 11113, 11121, + 11129, 11137, 11145, 11153, 11161, 11169, 11181, 11193, 11205, 11217, + 11229, 11241, 11253, 11265, 11277, 11289, 11301, 11313, 11325, 11337, + 11349, 11361, 11373, 11385, 11397, 11409, 11421, 11433, 11445, 11457, + 11469, 11481, 11493, 11505, 11517, 11529, 11541, 11553, 11565, 11577, + 11589, 11601, 11613, 11617, 11621, 11625, 11629, 11633, 11637, 11641, + 11645, 11649, 11653, 11657, 11661, 11665, 11669, 11673, 11677, 11681, + 11685, 11689, 11693, 11697, 11701, 11705, 11709, 11713, 11717, 11721, + 11725, 11729, 11733, 11737, 11741, 11745, 11749, 11753, 11757, 11761, + 11765, 11769, 11773, 11777, 11781, 11785, 11789, 11793, 11797, 11801, + 11805, 11809, 11813, 11817, 11821, 11824, 11824, 11824, 11824, 11824, + 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, + 11824, 11824, 11824, 11824, 11824, 11824, 11824}, + {11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, 11824, + 11824, 11824, 11825, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, 11840, + 11840, 11840, 11840, 11840, 11840, 11840, 11841, 11853, 11861, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, 11872, + 11872, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880}, + {11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, 11880, + 11880, 11880, 11880, 11880, 11881, 11885, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888}, + {11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, 11888, + 11888, 11889, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892}, + {11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, + 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11892, 11893, + 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, + 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, + 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, + 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, + 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, + 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, + 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, + 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, 11896, + 11896, 11896, 11896, 11897, 11900, 11900, 11900, 11900, 11900, 11900, + 11900, 11900, 11900, 11900, 11900, 11900, 11901}, + {11901, 11905, 11909, 11913, 11917, 11921, 11925, 11929, 11933, 11937, + 11941, 11945, 11949, 11953, 11957, 11961, 11965, 11969, 11973, 11977, + 11981, 11985, 11989, 11993, 11997, 12001, 12005, 12009, 12013, 12017, + 12021, 12025, 12029, 12033, 12037, 12041, 12045, 12049, 12053, 12057, + 12061, 12065, 12069, 12073, 12077, 12081, 12085, 12089, 12093, 12097, + 12101, 12105, 12109, 12113, 12117, 12121, 12125, 12129, 12133, 12137, + 12141, 12145, 12149, 12153, 12157, 12161, 12165, 12169, 12173, 12177, + 12181, 12185, 12189, 12193, 12197, 12201, 12205, 12209, 12213, 12217, + 12221, 12225, 12229, 12233, 12237, 12241, 12245, 12249, 12253, 12257, + 12261, 12265, 12269, 12273, 12277, 12281, 12285, 12289, 12293, 12297, + 12301, 12305, 12309, 12313, 12317, 12321, 12325, 12329, 12333, 12337, + 12341, 12345, 12349, 12353, 12357, 12361, 12365, 12369, 12373, 12377, + 12381, 12385, 12389, 12393, 12397, 12401, 12405, 12409, 12413, 12417, + 12421, 12425, 12429, 12433, 12437, 12441, 12445, 12449, 12453, 12457, + 12461, 12465, 12469, 12473, 12477, 12481, 12485, 12489, 12493, 12497, + 12501, 12505, 12509, 12513, 12517, 12521, 12525, 12529, 12533, 12537, + 12541, 12545, 12549, 12553, 12557, 12561, 12565, 12569, 12573, 12577, + 12581, 12585, 12589, 12593, 12597, 12601, 12605, 12609, 12613, 12617, + 12621, 12625, 12629, 12633, 12637, 12641, 12645, 12649, 12653, 12657, + 12661, 12665, 12669, 12673, 12677, 12681, 12685, 12689, 12693, 12697, + 12701, 12705, 12709, 12713, 12717, 12721, 12725, 12729, 12733, 12737, + 12741, 12745, 12749, 12753, 12756, 12756, 12756, 12756, 12756, 12756, + 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, + 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, + 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, 12756, + 12756, 12756, 12756, 12756, 12756, 12756, 12757}, + {12757, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, + 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, + 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, + 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, + 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, 12760, + 12760, 12760, 12760, 12760, 12761, 12764, 12765, 12769, 12773, 12776, + 12776, 12776, 12776, 12776, 12776, 12776, 12776, 12776, 12776, 12776, + 12776, 12776, 12776, 12776, 12776, 12776, 12776, 12784, 12784, 12792, + 12792, 12800, 12800, 12808, 12808, 12816, 12816, 12824, 12824, 12832, + 12832, 12840, 12840, 12848, 12848, 12856, 12856, 12864, 12864, 12872, + 12872, 12872, 12880, 12880, 12888, 12888, 12896, 12896, 12896, 12896, + 12896, 12896, 12896, 12904, 12912, 12912, 12920, 12928, 12928, 12936, + 12944, 12944, 12952, 12960, 12960, 12968, 12976, 12976, 12976, 12976, + 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, + 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12976, 12984, + 12984, 12984, 12984, 12984, 12984, 12985, 12993, 13000, 13000, 13009, + 13016, 13016, 13016, 13016, 13016, 13016, 13016, 13016, 13016, 13016, + 13016, 13016, 13016, 13024, 13024, 13032, 13032, 13040, 13040, 13048, + 13048, 13056, 13056, 13064, 13064, 13072, 13072, 13080, 13080, 13088, + 13088, 13096, 13096, 13104, 13104, 13112, 13112, 13112, 13120, 13120, + 13128, 13128, 13136, 13136, 13136, 13136, 13136, 13136, 13136, 13144, + 13152, 13152, 13160, 13168, 13168, 13176, 13184, 13184, 13192, 13200, + 13200, 13208, 13216, 13216, 13216, 13216, 13216, 13216, 13216, 13216, + 13216, 13216, 13216, 13216, 13216, 13216, 13216, 13216, 13216, 13216, + 13216, 13216, 13216, 13216, 13216, 13224, 13224, 13224, 13232, 13240, + 13248, 13256, 13256, 13256, 13256, 13265, 13272}, + {13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, + 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, + 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, + 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, + 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13272, 13273, + 13277, 13281, 13285, 13289, 13293, 13297, 13301, 13305, 13309, 13313, + 13317, 13321, 13325, 13329, 13333, 13337, 13341, 13345, 13349, 13353, + 13357, 13361, 13365, 13369, 13373, 13377, 13381, 13385, 13389, 13393, + 13397, 13401, 13405, 13409, 13413, 13417, 13421, 13425, 13429, 13433, + 13437, 13441, 13445, 13449, 13453, 13457, 13461, 13465, 13469, 13473, + 13477, 13481, 13485, 13489, 13493, 13497, 13501, 13505, 13509, 13513, + 13517, 13521, 13525, 13529, 13533, 13537, 13541, 13545, 13549, 13553, + 13557, 13561, 13565, 13569, 13573, 13577, 13581, 13585, 13589, 13593, + 13597, 13601, 13605, 13609, 13613, 13617, 13621, 13625, 13629, 13633, + 13637, 13641, 13645, 13648, 13648, 13648, 13649, 13653, 13657, 13661, + 13665, 13669, 13673, 13677, 13681, 13685, 13689, 13693, 13697, 13701, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, 13704, + 13704, 13704, 13704, 13704, 13704, 13704, 13705}, + {13705, 13717, 13729, 13741, 13753, 13765, 13777, 13789, 13801, 13813, + 13825, 13837, 13849, 13861, 13873, 13889, 13905, 13921, 13937, 13953, + 13969, 13985, 14001, 14017, 14033, 14049, 14065, 14081, 14097, 14113, + 14141, 14164, 14165, 14177, 14189, 14201, 14213, 14225, 14237, 14249, + 14261, 14273, 14285, 14297, 14309, 14321, 14333, 14345, 14357, 14369, + 14381, 14393, 14405, 14417, 14429, 14441, 14453, 14465, 14477, 14489, + 14501, 14513, 14525, 14537, 14549, 14561, 14573, 14585, 14597, 14601, + 14605, 14609, 14612, 14612, 14612, 14612, 14612, 14612, 14612, 14612, + 14613, 14625, 14633, 14641, 14649, 14657, 14665, 14673, 14681, 14689, + 14697, 14705, 14713, 14721, 14729, 14737, 14745, 14749, 14753, 14757, + 14761, 14765, 14769, 14773, 14777, 14781, 14785, 14789, 14793, 14797, + 14801, 14809, 14817, 14825, 14833, 14841, 14849, 14857, 14865, 14873, + 14881, 14889, 14897, 14905, 14913, 14933, 14949, 14956, 14957, 14961, + 14965, 14969, 14973, 14977, 14981, 14985, 14989, 14993, 14997, 15001, + 15005, 15009, 15013, 15017, 15021, 15025, 15029, 15033, 15037, 15041, + 15045, 15049, 15053, 15057, 15061, 15065, 15069, 15073, 15077, 15081, + 15085, 15089, 15093, 15097, 15101, 15105, 15109, 15113, 15117, 15121, + 15125, 15129, 15133, 15137, 15141, 15145, 15149, 15153, 15161, 15169, + 15177, 15185, 15193, 15201, 15209, 15217, 15225, 15233, 15241, 15249, + 15257, 15265, 15273, 15281, 15289, 15297, 15305, 15313, 15321, 15329, + 15337, 15345, 15357, 15369, 15381, 15389, 15401, 15409, 15421, 15425, + 15429, 15433, 15437, 15441, 15445, 15449, 15453, 15457, 15461, 15465, + 15469, 15473, 15477, 15481, 15485, 15489, 15493, 15497, 15501, 15505, + 15509, 15513, 15517, 15521, 15525, 15529, 15533, 15537, 15541, 15545, + 15549, 15553, 15557, 15561, 15565, 15569, 15573, 15577, 15581, 15585, + 15589, 15593, 15597, 15601, 15605, 15609, 15617}, + {15617, 15637, 15653, 15673, 15685, 15705, 15717, 15729, 15753, 15769, + 15781, 15793, 15805, 15821, 15837, 15853, 15869, 15885, 15901, 15917, + 15941, 15949, 15973, 15997, 16017, 16033, 16057, 16081, 16097, 16109, + 16121, 16137, 16153, 16173, 16193, 16205, 16217, 16233, 16245, 16257, + 16265, 16273, 16285, 16297, 16321, 16337, 16357, 16381, 16397, 16409, + 16421, 16445, 16461, 16485, 16497, 16517, 16529, 16545, 16557, 16573, + 16593, 16609, 16629, 16645, 16653, 16673, 16685, 16697, 16713, 16725, + 16737, 16749, 16769, 16785, 16793, 16817, 16829, 16849, 16865, 16881, + 16893, 16905, 16921, 16929, 16945, 16965, 16973, 16997, 17009, 17017, + 17025, 17033, 17041, 17049, 17057, 17065, 17073, 17081, 17089, 17101, + 17113, 17125, 17137, 17149, 17161, 17173, 17185, 17197, 17209, 17221, + 17233, 17245, 17257, 17269, 17281, 17289, 17297, 17309, 17317, 17325, + 17333, 17345, 17357, 17365, 17373, 17381, 17389, 17397, 17413, 17421, + 17429, 17437, 17445, 17453, 17461, 17469, 17477, 17489, 17505, 17513, + 17521, 17529, 17537, 17545, 17553, 17561, 17573, 17585, 17597, 17609, + 17617, 17625, 17633, 17641, 17649, 17657, 17665, 17673, 17681, 17689, + 17701, 17713, 17721, 17733, 17745, 17757, 17765, 17777, 17789, 17805, + 17813, 17825, 17837, 17849, 17861, 17881, 17905, 17913, 17921, 17929, + 17937, 17945, 17953, 17961, 17969, 17977, 17985, 17993, 18001, 18009, + 18017, 18025, 18033, 18041, 18049, 18065, 18073, 18081, 18089, 18105, + 18117, 18125, 18133, 18141, 18149, 18157, 18165, 18173, 18181, 18189, + 18197, 18209, 18217, 18225, 18237, 18249, 18257, 18273, 18285, 18293, + 18301, 18309, 18317, 18329, 18341, 18349, 18357, 18365, 18373, 18381, + 18389, 18397, 18405, 18413, 18425, 18437, 18449, 18461, 18473, 18485, + 18497, 18509, 18521, 18533, 18545, 18557, 18569, 18581, 18593, 18605, + 18617, 18629, 18641, 18653, 18665, 18677, 18688}, + {18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, 18688, + 18688, 18688, 18688, 18688, 18688, 18688, 18689, 18693, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696}, + {18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, 18696, + 18696, 18696, 18697, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, 18700, + 18700, 18700, 18701, 18705, 18709, 18712, 18712, 18712, 18713, 18717, + 18720, 18720, 18720, 18720, 18720, 18720, 18720}, + {18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, 18720, + 18720, 18720, 18721, 18725, 18729, 18733, 18736, 18736, 18736, 18736, + 18736, 18736, 18736, 18736, 18736, 18737, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, 18740, + 18740, 18740, 18740, 18740, 18740, 18740, 18740}, + {18740, 18744, 18748, 18752, 18756, 18760, 18764, 18768, 18772, 18776, + 18780, 18784, 18788, 18792, 18796, 18800, 18804, 18808, 18812, 18816, + 18820, 18824, 18828, 18832, 18836, 18840, 18844, 18848, 18852, 18856, + 18860, 18864, 18868, 18872, 18876, 18880, 18884, 18888, 18892, 18896, + 18900, 18904, 18908, 18912, 18916, 18920, 18924, 18928, 18932, 18936, + 18940, 18944, 18948, 18952, 18956, 18960, 18964, 18968, 18972, 18976, + 18980, 18984, 18988, 18992, 18996, 19000, 19004, 19008, 19012, 19016, + 19020, 19024, 19028, 19032, 19036, 19040, 19044, 19048, 19052, 19056, + 19060, 19064, 19068, 19072, 19076, 19080, 19084, 19088, 19092, 19096, + 19100, 19104, 19108, 19112, 19116, 19120, 19124, 19128, 19132, 19136, + 19140, 19144, 19148, 19152, 19156, 19160, 19164, 19168, 19172, 19176, + 19180, 19184, 19188, 19192, 19196, 19200, 19204, 19208, 19212, 19216, + 19220, 19224, 19228, 19232, 19236, 19240, 19244, 19248, 19252, 19256, + 19260, 19264, 19268, 19272, 19276, 19280, 19284, 19288, 19292, 19296, + 19300, 19304, 19308, 19312, 19316, 19320, 19324, 19328, 19332, 19336, + 19340, 19344, 19348, 19352, 19356, 19360, 19364, 19368, 19372, 19376, + 19380, 19384, 19388, 19392, 19396, 19400, 19404, 19408, 19412, 19416, + 19420, 19424, 19428, 19432, 19436, 19440, 19444, 19448, 19452, 19456, + 19460, 19464, 19468, 19472, 19476, 19480, 19484, 19488, 19492, 19496, + 19500, 19504, 19508, 19512, 19516, 19520, 19524, 19528, 19532, 19536, + 19540, 19544, 19548, 19552, 19556, 19560, 19564, 19568, 19572, 19576, + 19580, 19584, 19588, 19592, 19596, 19600, 19604, 19608, 19612, 19616, + 19620, 19624, 19628, 19632, 19636, 19640, 19644, 19648, 19652, 19656, + 19660, 19664, 19668, 19672, 19676, 19680, 19684, 19688, 19692, 19696, + 19700, 19704, 19708, 19712, 19716, 19720, 19724, 19728, 19732, 19736, + 19740, 19744, 19748, 19752, 19756, 19760, 19764}, + {19764, 19768, 19772, 19776, 19780, 19784, 19788, 19792, 19796, 19800, + 19804, 19808, 19812, 19816, 19820, 19820, 19820, 19824, 19824, 19828, + 19828, 19828, 19832, 19836, 19840, 19844, 19848, 19852, 19856, 19860, + 19864, 19868, 19868, 19872, 19872, 19876, 19876, 19876, 19880, 19884, + 19884, 19884, 19884, 19888, 19892, 19896, 19900, 19904, 19908, 19912, + 19916, 19920, 19924, 19928, 19932, 19936, 19940, 19944, 19948, 19952, + 19956, 19960, 19964, 19968, 19972, 19976, 19980, 19984, 19988, 19992, + 19996, 20000, 20004, 20008, 20012, 20016, 20020, 20024, 20028, 20032, + 20036, 20040, 20044, 20048, 20052, 20056, 20060, 20064, 20068, 20072, + 20076, 20080, 20084, 20088, 20092, 20096, 20100, 20104, 20108, 20112, + 20116, 20120, 20124, 20128, 20132, 20136, 20140, 20144, 20148, 20152, + 20156, 20156, 20156, 20160, 20164, 20168, 20172, 20176, 20180, 20184, + 20188, 20192, 20196, 20200, 20204, 20208, 20212, 20216, 20220, 20224, + 20228, 20232, 20236, 20240, 20244, 20248, 20252, 20256, 20260, 20264, + 20268, 20272, 20276, 20280, 20284, 20288, 20292, 20296, 20300, 20304, + 20308, 20312, 20316, 20320, 20324, 20328, 20332, 20336, 20340, 20344, + 20348, 20352, 20356, 20360, 20364, 20368, 20372, 20376, 20380, 20384, + 20388, 20392, 20396, 20400, 20404, 20408, 20412, 20416, 20420, 20424, + 20428, 20432, 20436, 20440, 20444, 20448, 20452, 20456, 20460, 20464, + 20468, 20472, 20476, 20480, 20484, 20488, 20492, 20496, 20500, 20504, + 20508, 20512, 20516, 20520, 20524, 20528, 20532, 20536, 20540, 20544, + 20548, 20552, 20556, 20560, 20564, 20568, 20572, 20576, 20580, 20580, + 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, + 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, + 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, 20580, + 20580, 20580, 20580, 20580, 20580, 20580, 20581}, + {20581, 20589, 20597, 20605, 20617, 20629, 20637, 20644, 20644, 20644, + 20644, 20644, 20644, 20644, 20644, 20644, 20644, 20644, 20644, 20645, + 20653, 20661, 20669, 20677, 20684, 20684, 20684, 20684, 20684, 20684, + 20692, 20692, 20701, 20705, 20709, 20713, 20717, 20721, 20725, 20729, + 20733, 20737, 20740, 20748, 20756, 20768, 20780, 20788, 20796, 20804, + 20812, 20820, 20828, 20836, 20844, 20852, 20852, 20860, 20868, 20876, + 20884, 20892, 20892, 20900, 20900, 20908, 20916, 20916, 20924, 20932, + 20932, 20940, 20948, 20956, 20964, 20972, 20980, 20988, 20996, 21005, + 21013, 21017, 21021, 21025, 21029, 21033, 21037, 21041, 21045, 21049, + 21053, 21057, 21061, 21065, 21069, 21073, 21077, 21081, 21085, 21089, + 21093, 21097, 21101, 21105, 21109, 21113, 21117, 21121, 21125, 21129, + 21133, 21137, 21141, 21145, 21149, 21153, 21157, 21161, 21165, 21169, + 21173, 21177, 21181, 21185, 21189, 21193, 21197, 21201, 21205, 21209, + 21213, 21217, 21221, 21225, 21229, 21233, 21237, 21241, 21245, 21249, + 21253, 21257, 21261, 21265, 21269, 21273, 21277, 21281, 21285, 21289, + 21293, 21297, 21301, 21305, 21309, 21313, 21317, 21321, 21325, 21329, + 21333, 21337, 21341, 21345, 21349, 21357, 21365, 21369, 21373, 21377, + 21381, 21385, 21389, 21393, 21397, 21401, 21405, 21413, 21420, 21420, + 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, + 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, + 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, 21420, + 21420, 21421, 21425, 21429, 21433, 21437, 21441, 21445, 21449, 21453, + 21457, 21461, 21469, 21473, 21477, 21481, 21485, 21489, 21493, 21497, + 21501, 21505, 21509, 21513, 21517, 21529, 21541, 21553, 21565, 21577, + 21589, 21601, 21613, 21625, 21637, 21649, 21661, 21673, 21685, 21697, + 21709, 21721, 21733, 21737, 21741, 21745, 21749}, + {21749, 21761, 21773, 21785, 21797, 21809, 21817, 21825, 21833, 21841, + 21849, 21857, 21865, 21873, 21881, 21889, 21897, 21905, 21913, 21921, + 21929, 21937, 21945, 21953, 21961, 21969, 21977, 21985, 21993, 22001, + 22009, 22017, 22025, 22033, 22041, 22049, 22057, 22065, 22073, 22081, + 22089, 22097, 22105, 22113, 22121, 22129, 22137, 22145, 22153, 22161, + 22169, 22177, 22185, 22193, 22201, 22209, 22217, 22225, 22233, 22241, + 22249, 22257, 22265, 22273, 22281, 22289, 22297, 22305, 22313, 22321, + 22329, 22337, 22345, 22353, 22361, 22369, 22377, 22385, 22393, 22401, + 22409, 22417, 22425, 22433, 22441, 22449, 22457, 22465, 22473, 22481, + 22489, 22497, 22505, 22513, 22521, 22533, 22545, 22557, 22569, 22581, + 22593, 22605, 22617, 22629, 22641, 22653, 22665, 22673, 22681, 22689, + 22697, 22705, 22713, 22721, 22729, 22737, 22745, 22753, 22761, 22769, + 22777, 22785, 22793, 22801, 22809, 22817, 22825, 22833, 22841, 22849, + 22857, 22865, 22873, 22881, 22889, 22897, 22905, 22913, 22921, 22929, + 22937, 22945, 22953, 22961, 22969, 22977, 22985, 22993, 23001, 23009, + 23017, 23025, 23037, 23049, 23061, 23073, 23085, 23093, 23101, 23109, + 23117, 23125, 23133, 23141, 23149, 23157, 23165, 23173, 23181, 23189, + 23197, 23205, 23213, 23221, 23229, 23237, 23245, 23253, 23261, 23269, + 23277, 23285, 23293, 23301, 23309, 23317, 23325, 23333, 23341, 23349, + 23357, 23365, 23373, 23381, 23389, 23397, 23405, 23413, 23421, 23429, + 23437, 23445, 23453, 23461, 23469, 23477, 23485, 23493, 23501, 23509, + 23517, 23525, 23533, 23541, 23549, 23557, 23565, 23573, 23581, 23589, + 23597, 23605, 23613, 23621, 23633, 23645, 23653, 23661, 23669, 23677, + 23685, 23693, 23701, 23709, 23717, 23725, 23733, 23741, 23749, 23757, + 23765, 23773, 23781, 23793, 23805, 23817, 23825, 23833, 23841, 23849, + 23857, 23865, 23873, 23881, 23889, 23897, 23905}, + {23905, 23913, 23921, 23929, 23937, 23945, 23953, 23961, 23969, 23977, + 23985, 23993, 24001, 24009, 24017, 24025, 24033, 24041, 24049, 24057, + 24065, 24073, 24081, 24089, 24097, 24105, 24113, 24121, 24129, 24137, + 24145, 24153, 24161, 24169, 24177, 24185, 24193, 24201, 24209, 24217, + 24225, 24233, 24241, 24249, 24257, 24265, 24273, 24281, 24289, 24297, + 24305, 24313, 24321, 24329, 24337, 24345, 24353, 24361, 24369, 24377, + 24385, 24393, 24400, 24400, 24400, 24400, 24400, 24400, 24400, 24400, + 24400, 24400, 24400, 24400, 24400, 24400, 24400, 24400, 24400, 24400, + 24401, 24413, 24425, 24437, 24449, 24461, 24473, 24485, 24497, 24509, + 24521, 24533, 24545, 24557, 24569, 24581, 24593, 24605, 24617, 24629, + 24641, 24653, 24665, 24677, 24689, 24701, 24713, 24725, 24737, 24749, + 24761, 24773, 24785, 24797, 24809, 24821, 24833, 24845, 24857, 24869, + 24881, 24893, 24905, 24917, 24929, 24941, 24953, 24965, 24977, 24989, + 25001, 25013, 25025, 25037, 25049, 25061, 25073, 25085, 25097, 25109, + 25121, 25133, 25145, 25157, 25168, 25168, 25169, 25181, 25193, 25205, + 25217, 25229, 25241, 25253, 25265, 25277, 25289, 25301, 25313, 25325, + 25337, 25349, 25361, 25373, 25385, 25397, 25409, 25421, 25433, 25445, + 25457, 25469, 25481, 25493, 25505, 25517, 25529, 25541, 25553, 25565, + 25577, 25589, 25601, 25613, 25625, 25637, 25649, 25661, 25673, 25685, + 25697, 25709, 25721, 25733, 25745, 25757, 25769, 25781, 25793, 25805, + 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, + 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, + 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, + 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, 25816, + 25817, 25829, 25841, 25857, 25873, 25889, 25905, 25921, 25937, 25953, + 25965, 26037, 26069, 26084, 26084, 26084, 26084}, + {26084, 26084, 26084, 26084, 26084, 26084, 26084, 26084, 26084, 26084, + 26084, 26084, 26084, 26084, 26084, 26084, 26085, 26089, 26093, 26097, + 26101, 26105, 26109, 26113, 26117, 26121, 26132, 26132, 26132, 26132, + 26132, 26132, 26132, 26132, 26132, 26132, 26132, 26132, 26132, 26132, + 26132, 26132, 26132, 26132, 26132, 26132, 26132, 26132, 26133, 26141, + 26145, 26149, 26153, 26157, 26161, 26165, 26169, 26173, 26177, 26181, + 26185, 26189, 26193, 26197, 26201, 26205, 26209, 26213, 26217, 26220, + 26220, 26221, 26225, 26229, 26237, 26245, 26253, 26261, 26265, 26269, + 26273, 26277, 26281, 26284, 26285, 26289, 26293, 26297, 26301, 26305, + 26309, 26313, 26317, 26321, 26325, 26329, 26333, 26337, 26341, 26345, + 26349, 26353, 26357, 26360, 26361, 26365, 26369, 26373, 26376, 26376, + 26376, 26376, 26377, 26385, 26393, 26400, 26401, 26408, 26409, 26417, + 26425, 26433, 26441, 26449, 26457, 26465, 26473, 26481, 26489, 26493, + 26501, 26509, 26517, 26525, 26533, 26541, 26549, 26557, 26565, 26573, + 26581, 26589, 26593, 26597, 26601, 26605, 26609, 26613, 26617, 26621, + 26625, 26629, 26633, 26637, 26641, 26645, 26649, 26653, 26657, 26661, + 26665, 26669, 26673, 26677, 26681, 26685, 26689, 26693, 26697, 26701, + 26705, 26709, 26713, 26717, 26721, 26725, 26729, 26733, 26737, 26741, + 26745, 26749, 26753, 26757, 26761, 26765, 26769, 26773, 26777, 26781, + 26785, 26789, 26793, 26797, 26801, 26805, 26809, 26813, 26817, 26821, + 26825, 26829, 26833, 26837, 26841, 26845, 26849, 26853, 26857, 26861, + 26865, 26869, 26873, 26877, 26881, 26885, 26889, 26893, 26897, 26901, + 26905, 26909, 26913, 26917, 26921, 26925, 26929, 26933, 26937, 26941, + 26945, 26949, 26953, 26957, 26961, 26965, 26969, 26973, 26977, 26981, + 26985, 26989, 26993, 26997, 27001, 27005, 27017, 27029, 27041, 27053, + 27065, 27077, 27085, 27092, 27092, 27092, 27092}, + {27092, 27093, 27097, 27101, 27105, 27109, 27113, 27117, 27121, 27125, + 27129, 27133, 27137, 27141, 27145, 27149, 27153, 27157, 27161, 27165, + 27169, 27173, 27177, 27181, 27185, 27189, 27193, 27197, 27201, 27205, + 27209, 27213, 27217, 27221, 27225, 27229, 27233, 27237, 27241, 27245, + 27249, 27253, 27257, 27261, 27265, 27269, 27273, 27277, 27281, 27285, + 27289, 27293, 27297, 27301, 27305, 27309, 27313, 27317, 27321, 27325, + 27329, 27333, 27337, 27341, 27345, 27349, 27353, 27357, 27361, 27365, + 27369, 27373, 27377, 27381, 27385, 27389, 27393, 27397, 27401, 27405, + 27409, 27413, 27417, 27421, 27425, 27429, 27433, 27437, 27441, 27445, + 27449, 27453, 27457, 27461, 27465, 27469, 27473, 27477, 27481, 27485, + 27489, 27493, 27497, 27501, 27505, 27509, 27513, 27517, 27521, 27525, + 27529, 27533, 27537, 27541, 27545, 27549, 27553, 27557, 27561, 27565, + 27569, 27573, 27577, 27581, 27585, 27589, 27593, 27597, 27601, 27605, + 27609, 27613, 27617, 27621, 27625, 27629, 27633, 27637, 27641, 27645, + 27649, 27653, 27657, 27661, 27665, 27669, 27673, 27677, 27681, 27685, + 27689, 27693, 27697, 27701, 27705, 27709, 27713, 27717, 27721, 27725, + 27729, 27733, 27737, 27741, 27745, 27749, 27753, 27757, 27761, 27765, + 27769, 27773, 27777, 27781, 27785, 27789, 27793, 27797, 27801, 27805, + 27809, 27813, 27817, 27821, 27825, 27829, 27833, 27837, 27841, 27845, + 27849, 27852, 27852, 27852, 27853, 27857, 27861, 27865, 27869, 27873, + 27876, 27876, 27877, 27881, 27885, 27889, 27893, 27897, 27900, 27900, + 27901, 27905, 27909, 27913, 27917, 27921, 27924, 27924, 27925, 27929, + 27933, 27936, 27936, 27936, 27937, 27941, 27945, 27949, 27957, 27961, + 27965, 27968, 27969, 27973, 27977, 27981, 27985, 27989, 27993, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996}, + {27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, + 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27996, 27997, + 28001, 28005, 28009, 28013, 28016, 28017, 28021, 28025, 28029, 28033, + 28037, 28041, 28045, 28049, 28053, 28057, 28061, 28065, 28069, 28073, + 28077, 28081, 28085, 28089, 28093, 28097, 28101, 28105, 28109, 28113, + 28117, 28121, 28125, 28129, 28133, 28137, 28141, 28145, 28149, 28153, + 28157, 28161, 28165, 28169, 28173, 28177, 28181, 28184, 28185, 28189, + 28193, 28197, 28201, 28205, 28209, 28213, 28217, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220}, + {28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, 28220, + 28220, 28220, 28220, 28220, 28220, 28228, 28228, 28236, 28236, 28236, + 28236, 28236, 28236, 28236, 28236, 28236, 28236, 28236, 28236, 28236, + 28236, 28236, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244}, + {28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28244, + 28244, 28244, 28244, 28244, 28244, 28244, 28244, 28252, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260}, + {28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, 28260, + 28260, 28260, 28260, 28260, 28260, 28260, 28268, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276}, + {28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, + 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28276, 28284, 28292, + 28292, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300}, + {28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28300, + 28300, 28300, 28300, 28300, 28300, 28300, 28300, 28308, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316}, + {28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28316, + 28316, 28316, 28316, 28316, 28316, 28316, 28316, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324}, + {28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, 28324, + 28324, 28324, 28324, 28324, 28324, 28332, 28340, 28352, 28364, 28376, + 28388, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, + 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, + 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, + 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, + 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, + 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, + 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, + 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, + 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28400, 28408, 28416, + 28428, 28440, 28452, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464}, + {28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, 28464, + 28464, 28464, 28464, 28464, 28464, 28464, 28465}, + {28465, 28469, 28473, 28477, 28481, 28485, 28489, 28493, 28497, 28501, + 28505, 28509, 28513, 28517, 28521, 28525, 28529, 28533, 28537, 28541, + 28545, 28549, 28553, 28557, 28561, 28565, 28569, 28573, 28577, 28581, + 28585, 28589, 28593, 28597, 28601, 28605, 28609, 28613, 28617, 28621, + 28625, 28629, 28633, 28637, 28641, 28645, 28649, 28653, 28657, 28661, + 28665, 28669, 28673, 28677, 28681, 28685, 28689, 28693, 28697, 28701, + 28705, 28709, 28713, 28717, 28721, 28725, 28729, 28733, 28737, 28741, + 28745, 28749, 28753, 28757, 28761, 28765, 28769, 28773, 28777, 28781, + 28785, 28789, 28793, 28797, 28801, 28804, 28805, 28809, 28813, 28817, + 28821, 28825, 28829, 28833, 28837, 28841, 28845, 28849, 28853, 28857, + 28861, 28865, 28869, 28873, 28877, 28881, 28885, 28889, 28893, 28897, + 28901, 28905, 28909, 28913, 28917, 28921, 28925, 28929, 28933, 28937, + 28941, 28945, 28949, 28953, 28957, 28961, 28965, 28969, 28973, 28977, + 28981, 28985, 28989, 28993, 28997, 29001, 29005, 29009, 29013, 29017, + 29021, 29025, 29029, 29033, 29037, 29041, 29045, 29049, 29053, 29057, + 29061, 29065, 29069, 29073, 29077, 29081, 29085, 29088, 29089, 29093, + 29096, 29096, 29097, 29100, 29100, 29101, 29105, 29108, 29108, 29109, + 29113, 29117, 29121, 29124, 29125, 29129, 29133, 29137, 29141, 29145, + 29149, 29153, 29157, 29161, 29165, 29169, 29172, 29173, 29176, 29177, + 29181, 29185, 29189, 29193, 29197, 29201, 29204, 29205, 29209, 29213, + 29217, 29221, 29225, 29229, 29233, 29237, 29241, 29245, 29249, 29253, + 29257, 29261, 29265, 29269, 29273, 29277, 29281, 29285, 29289, 29293, + 29297, 29301, 29305, 29309, 29313, 29317, 29321, 29325, 29329, 29333, + 29337, 29341, 29345, 29349, 29353, 29357, 29361, 29365, 29369, 29373, + 29377, 29381, 29385, 29389, 29393, 29397, 29401, 29405, 29409, 29413, + 29417, 29421, 29425, 29429, 29433, 29437, 29441}, + {29441, 29445, 29449, 29453, 29457, 29461, 29464, 29465, 29469, 29473, + 29477, 29480, 29480, 29481, 29485, 29489, 29493, 29497, 29501, 29505, + 29509, 29512, 29513, 29517, 29521, 29525, 29529, 29533, 29537, 29540, + 29541, 29545, 29549, 29553, 29557, 29561, 29565, 29569, 29573, 29577, + 29581, 29585, 29589, 29593, 29597, 29601, 29605, 29609, 29613, 29617, + 29621, 29625, 29629, 29633, 29637, 29641, 29645, 29649, 29652, 29653, + 29657, 29661, 29665, 29668, 29669, 29673, 29677, 29681, 29685, 29688, + 29689, 29692, 29692, 29692, 29693, 29697, 29701, 29705, 29709, 29713, + 29717, 29720, 29721, 29725, 29729, 29733, 29737, 29741, 29745, 29749, + 29753, 29757, 29761, 29765, 29769, 29773, 29777, 29781, 29785, 29789, + 29793, 29797, 29801, 29805, 29809, 29813, 29817, 29821, 29825, 29829, + 29833, 29837, 29841, 29845, 29849, 29853, 29857, 29861, 29865, 29869, + 29873, 29877, 29881, 29885, 29889, 29893, 29897, 29901, 29905, 29909, + 29913, 29917, 29921, 29925, 29929, 29933, 29937, 29941, 29945, 29949, + 29953, 29957, 29961, 29965, 29969, 29973, 29977, 29981, 29985, 29989, + 29993, 29997, 30001, 30005, 30009, 30013, 30017, 30021, 30025, 30029, + 30033, 30037, 30041, 30045, 30049, 30053, 30057, 30061, 30065, 30069, + 30073, 30077, 30081, 30085, 30089, 30093, 30097, 30101, 30105, 30109, + 30113, 30117, 30121, 30125, 30129, 30133, 30137, 30141, 30145, 30149, + 30153, 30157, 30161, 30165, 30169, 30173, 30177, 30181, 30185, 30189, + 30193, 30197, 30201, 30205, 30209, 30213, 30217, 30221, 30225, 30229, + 30233, 30237, 30241, 30245, 30249, 30253, 30257, 30261, 30265, 30269, + 30273, 30277, 30281, 30285, 30289, 30293, 30297, 30301, 30305, 30309, + 30313, 30317, 30321, 30325, 30329, 30333, 30337, 30341, 30345, 30349, + 30353, 30357, 30361, 30365, 30369, 30373, 30377, 30381, 30385, 30389, + 30393, 30397, 30401, 30405, 30409, 30413, 30417}, + {30417, 30421, 30425, 30429, 30433, 30437, 30441, 30445, 30449, 30453, + 30457, 30461, 30465, 30469, 30473, 30477, 30481, 30485, 30489, 30493, + 30497, 30501, 30505, 30509, 30513, 30517, 30521, 30525, 30529, 30533, + 30537, 30541, 30545, 30549, 30553, 30557, 30561, 30565, 30569, 30573, + 30577, 30581, 30585, 30589, 30593, 30597, 30601, 30605, 30609, 30613, + 30617, 30621, 30625, 30629, 30633, 30637, 30641, 30645, 30649, 30653, + 30657, 30661, 30665, 30669, 30673, 30677, 30681, 30685, 30689, 30693, + 30697, 30701, 30705, 30709, 30713, 30717, 30721, 30725, 30729, 30733, + 30737, 30741, 30745, 30749, 30753, 30757, 30761, 30765, 30769, 30773, + 30777, 30781, 30785, 30789, 30793, 30797, 30801, 30805, 30809, 30813, + 30817, 30821, 30825, 30829, 30833, 30837, 30841, 30845, 30849, 30853, + 30857, 30861, 30865, 30869, 30873, 30877, 30881, 30885, 30889, 30893, + 30897, 30901, 30905, 30909, 30913, 30917, 30921, 30925, 30929, 30933, + 30937, 30941, 30945, 30949, 30953, 30957, 30961, 30965, 30969, 30973, + 30977, 30981, 30985, 30989, 30993, 30997, 31001, 31005, 31009, 31013, + 31017, 31021, 31025, 31029, 31033, 31037, 31041, 31045, 31049, 31053, + 31057, 31061, 31065, 31069, 31073, 31077, 31080, 31080, 31081, 31085, + 31089, 31093, 31097, 31101, 31105, 31109, 31113, 31117, 31121, 31125, + 31129, 31133, 31137, 31141, 31145, 31149, 31153, 31157, 31161, 31165, + 31169, 31173, 31177, 31181, 31185, 31189, 31193, 31197, 31201, 31205, + 31209, 31213, 31217, 31221, 31225, 31229, 31233, 31237, 31241, 31245, + 31249, 31253, 31257, 31261, 31265, 31269, 31273, 31277, 31281, 31285, + 31289, 31293, 31297, 31301, 31305, 31309, 31313, 31317, 31321, 31325, + 31329, 31333, 31337, 31341, 31345, 31349, 31353, 31357, 31361, 31365, + 31369, 31373, 31377, 31381, 31385, 31389, 31393, 31397, 31401, 31405, + 31409, 31413, 31417, 31421, 31425, 31429, 31433}, + {31433, 31437, 31441, 31445, 31449, 31453, 31457, 31461, 31465, 31469, + 31473, 31477, 31481, 31485, 31489, 31493, 31497, 31501, 31505, 31509, + 31513, 31517, 31521, 31525, 31529, 31533, 31537, 31541, 31545, 31549, + 31553, 31557, 31561, 31565, 31569, 31573, 31577, 31581, 31585, 31589, + 31593, 31597, 31601, 31605, 31609, 31613, 31617, 31621, 31625, 31629, + 31633, 31637, 31641, 31645, 31649, 31653, 31657, 31661, 31665, 31669, + 31673, 31677, 31681, 31685, 31689, 31693, 31697, 31701, 31705, 31709, + 31713, 31717, 31721, 31725, 31729, 31733, 31737, 31741, 31745, 31749, + 31753, 31757, 31761, 31765, 31769, 31773, 31777, 31781, 31785, 31789, + 31793, 31797, 31801, 31805, 31809, 31813, 31817, 31821, 31825, 31829, + 31833, 31837, 31841, 31845, 31849, 31853, 31857, 31861, 31865, 31869, + 31873, 31877, 31881, 31885, 31889, 31893, 31897, 31901, 31905, 31909, + 31913, 31917, 31921, 31925, 31929, 31933, 31937, 31941, 31945, 31949, + 31953, 31957, 31961, 31965, 31969, 31973, 31977, 31981, 31985, 31989, + 31993, 31997, 32001, 32005, 32009, 32013, 32017, 32021, 32025, 32029, + 32033, 32037, 32041, 32045, 32049, 32053, 32057, 32061, 32065, 32069, + 32073, 32077, 32081, 32085, 32089, 32093, 32097, 32101, 32105, 32109, + 32113, 32117, 32121, 32125, 32129, 32133, 32137, 32141, 32145, 32149, + 32153, 32157, 32161, 32165, 32169, 32173, 32177, 32181, 32185, 32189, + 32193, 32197, 32201, 32205, 32209, 32213, 32217, 32221, 32225, 32229, + 32233, 32237, 32241, 32245, 32248, 32248, 32249, 32253, 32257, 32261, + 32265, 32269, 32273, 32277, 32281, 32285, 32289, 32293, 32297, 32301, + 32305, 32309, 32313, 32317, 32321, 32325, 32329, 32333, 32337, 32341, + 32345, 32349, 32353, 32357, 32361, 32365, 32369, 32373, 32377, 32381, + 32385, 32389, 32393, 32397, 32401, 32405, 32409, 32413, 32417, 32421, + 32425, 32429, 32433, 32437, 32441, 32445, 32448}, + {32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, + 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, + 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, + 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, + 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32448, 32449, 32453, + 32457, 32461, 32465, 32469, 32473, 32477, 32481, 32485, 32489, 32493, + 32497, 32501, 32505, 32509, 32513, 32517, 32521, 32525, 32529, 32533, + 32537, 32541, 32545, 32549, 32553, 32557, 32561, 32565, 32569, 32573, + 32577, 32581, 32585, 32589, 32593, 32597, 32601, 32605, 32609, 32613, + 32617, 32621, 32625, 32629, 32633, 32637, 32641, 32645, 32649, 32653, + 32657, 32661, 32665, 32669, 32673, 32677, 32681, 32685, 32689, 32693, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696}, + {32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, 32696, + 32696, 32696, 32696, 32696, 32696, 32696, 32697}, + {32697, 32701, 32705, 32709, 32712, 32713, 32717, 32721, 32725, 32729, + 32733, 32737, 32741, 32745, 32749, 32753, 32757, 32761, 32765, 32769, + 32773, 32777, 32781, 32785, 32789, 32793, 32797, 32801, 32805, 32809, + 32813, 32817, 32820, 32821, 32825, 32828, 32829, 32832, 32832, 32833, + 32836, 32837, 32841, 32845, 32849, 32853, 32857, 32861, 32865, 32869, + 32873, 32876, 32877, 32881, 32885, 32889, 32892, 32893, 32896, 32897, + 32900, 32900, 32900, 32900, 32900, 32900, 32901, 32904, 32904, 32904, + 32904, 32905, 32908, 32909, 32912, 32913, 32916, 32917, 32921, 32925, + 32928, 32929, 32933, 32936, 32937, 32940, 32940, 32941, 32944, 32945, + 32948, 32949, 32952, 32953, 32956, 32957, 32960, 32961, 32965, 32968, + 32969, 32972, 32972, 32973, 32977, 32981, 32985, 32988, 32989, 32993, + 32997, 33001, 33005, 33009, 33013, 33016, 33017, 33021, 33025, 33029, + 33032, 33033, 33037, 33041, 33045, 33048, 33049, 33052, 33053, 33057, + 33061, 33065, 33069, 33073, 33077, 33081, 33085, 33089, 33092, 33093, + 33097, 33101, 33105, 33109, 33113, 33117, 33121, 33125, 33129, 33133, + 33137, 33141, 33145, 33149, 33153, 33157, 33160, 33160, 33160, 33160, + 33160, 33161, 33165, 33169, 33172, 33173, 33177, 33181, 33185, 33189, + 33192, 33193, 33197, 33201, 33205, 33209, 33213, 33217, 33221, 33225, + 33229, 33233, 33237, 33241, 33245, 33249, 33253, 33257, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260}, + {33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, 33260, + 33260, 33260, 33260, 33260, 33260, 33260, 33261}, + {33261, 33269, 33277, 33285, 33293, 33301, 33309, 33317, 33325, 33333, + 33341, 33348, 33348, 33348, 33348, 33348, 33349, 33361, 33373, 33385, + 33397, 33409, 33421, 33433, 33445, 33457, 33469, 33481, 33493, 33505, + 33517, 33529, 33541, 33553, 33565, 33577, 33589, 33601, 33613, 33625, + 33637, 33649, 33661, 33673, 33677, 33681, 33689, 33696, 33697, 33701, + 33705, 33709, 33713, 33717, 33721, 33725, 33729, 33733, 33737, 33741, + 33745, 33749, 33753, 33757, 33761, 33765, 33769, 33773, 33777, 33781, + 33785, 33789, 33793, 33797, 33801, 33809, 33817, 33825, 33833, 33845, + 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, + 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, 33852, + 33852, 33852, 33852, 33852, 33852, 33852, 33853, 33861, 33869, 33876, + 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, + 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, + 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, 33876, + 33876, 33876, 33876, 33876, 33877, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, 33884, + 33884, 33884, 33884, 33884, 33884, 33884, 33885}, + {33885, 33893, 33901, 33904, 33904, 33904, 33904, 33904, 33904, 33904, + 33904, 33904, 33904, 33904, 33904, 33904, 33905, 33909, 33913, 33917, + 33925, 33929, 33933, 33937, 33941, 33945, 33949, 33953, 33957, 33961, + 33965, 33969, 33973, 33977, 33981, 33985, 33989, 33993, 33997, 34001, + 34005, 34009, 34013, 34017, 34021, 34025, 34029, 34033, 34037, 34041, + 34045, 34049, 34053, 34057, 34061, 34065, 34069, 34073, 34077, 34081, + 34084, 34084, 34084, 34084, 34085, 34097, 34109, 34121, 34133, 34145, + 34157, 34169, 34181, 34192, 34192, 34192, 34192, 34192, 34192, 34192, + 34193, 34197, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200}, + {34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, 34200, + 34201, 34205, 34209, 34213, 34217, 34221, 34225, 34229, 34233, 34237, + 34240, 34240, 34240, 34240, 34240, 34240, 34240}, + {34240, 34244, 34248, 34252, 34256, 34260, 34264, 34268, 34272, 34276, + 34280, 34284, 34288, 34292, 34296, 34300, 34304, 34308, 34312, 34316, + 34320, 34324, 34328, 34332, 34336, 34340, 34344, 34348, 34352, 34356, + 34360, 34364, 34368, 34372, 34376, 34380, 34384, 34388, 34392, 34396, + 34400, 34404, 34408, 34412, 34416, 34420, 34424, 34428, 34432, 34436, + 34440, 34444, 34448, 34452, 34456, 34460, 34464, 34468, 34472, 34476, + 34480, 34484, 34488, 34492, 34496, 34500, 34504, 34508, 34512, 34516, + 34520, 34524, 34528, 34532, 34536, 34540, 34544, 34548, 34552, 34556, + 34560, 34564, 34568, 34572, 34576, 34580, 34584, 34588, 34592, 34596, + 34600, 34604, 34608, 34612, 34616, 34620, 34624, 34628, 34632, 34636, + 34640, 34644, 34648, 34652, 34656, 34660, 34664, 34668, 34672, 34676, + 34680, 34684, 34688, 34692, 34696, 34700, 34704, 34708, 34712, 34716, + 34720, 34724, 34728, 34732, 34736, 34740, 34744, 34748, 34752, 34756, + 34760, 34764, 34768, 34772, 34776, 34780, 34784, 34788, 34792, 34796, + 34800, 34804, 34808, 34812, 34816, 34820, 34824, 34828, 34832, 34836, + 34840, 34844, 34848, 34852, 34856, 34860, 34864, 34868, 34872, 34876, + 34880, 34884, 34888, 34892, 34896, 34900, 34904, 34908, 34912, 34916, + 34920, 34924, 34928, 34932, 34936, 34940, 34944, 34948, 34952, 34956, + 34960, 34964, 34968, 34972, 34976, 34980, 34984, 34988, 34992, 34996, + 35000, 35004, 35008, 35012, 35016, 35020, 35024, 35028, 35032, 35036, + 35040, 35044, 35048, 35052, 35056, 35060, 35064, 35068, 35072, 35076, + 35080, 35084, 35088, 35092, 35096, 35100, 35104, 35108, 35112, 35116, + 35120, 35124, 35128, 35132, 35136, 35140, 35144, 35148, 35152, 35156, + 35160, 35164, 35168, 35172, 35176, 35180, 35184, 35188, 35192, 35196, + 35200, 35204, 35208, 35212, 35216, 35220, 35224, 35228, 35232, 35236, + 35240, 35244, 35248, 35252, 35256, 35260, 35264}, + {35264, 35268, 35272, 35276, 35280, 35284, 35288, 35292, 35296, 35300, + 35304, 35308, 35312, 35316, 35320, 35324, 35328, 35332, 35336, 35340, + 35344, 35348, 35352, 35356, 35360, 35364, 35368, 35372, 35376, 35380, + 35384, 35388, 35392, 35396, 35400, 35404, 35408, 35412, 35416, 35420, + 35424, 35428, 35432, 35436, 35440, 35444, 35448, 35452, 35456, 35460, + 35464, 35468, 35472, 35476, 35480, 35484, 35488, 35492, 35496, 35500, + 35504, 35508, 35512, 35516, 35520, 35524, 35528, 35532, 35536, 35540, + 35544, 35548, 35552, 35556, 35560, 35564, 35568, 35572, 35576, 35580, + 35584, 35588, 35592, 35596, 35600, 35604, 35608, 35612, 35616, 35620, + 35624, 35628, 35632, 35636, 35640, 35644, 35648, 35652, 35656, 35660, + 35664, 35668, 35672, 35676, 35680, 35684, 35688, 35692, 35696, 35700, + 35704, 35708, 35712, 35716, 35720, 35724, 35728, 35732, 35736, 35740, + 35744, 35748, 35752, 35756, 35760, 35764, 35768, 35772, 35776, 35780, + 35784, 35788, 35792, 35796, 35800, 35804, 35808, 35812, 35816, 35820, + 35824, 35828, 35832, 35836, 35840, 35844, 35848, 35852, 35856, 35860, + 35864, 35868, 35872, 35876, 35880, 35884, 35888, 35892, 35896, 35900, + 35904, 35908, 35912, 35916, 35920, 35924, 35928, 35932, 35936, 35940, + 35944, 35948, 35952, 35956, 35960, 35964, 35968, 35972, 35976, 35980, + 35984, 35988, 35992, 35996, 36000, 36004, 36008, 36012, 36016, 36020, + 36024, 36028, 36032, 36036, 36040, 36044, 36048, 36052, 36056, 36060, + 36064, 36068, 36072, 36076, 36080, 36084, 36088, 36092, 36096, 36100, + 36104, 36108, 36112, 36116, 36120, 36124, 36128, 36132, 36136, 36140, + 36144, 36148, 36152, 36156, 36160, 36164, 36168, 36172, 36176, 36180, + 36184, 36188, 36192, 36196, 36200, 36204, 36208, 36212, 36216, 36220, + 36224, 36228, 36232, 36236, 36240, 36244, 36248, 36252, 36256, 36260, + 36264, 36268, 36272, 36276, 36280, 36284, 36288}, + {36288, 36292, 36296, 36300, 36304, 36308, 36312, 36316, 36320, 36324, + 36328, 36332, 36336, 36340, 36344, 36348, 36352, 36356, 36360, 36364, + 36368, 36372, 36376, 36380, 36384, 36388, 36392, 36396, 36400, 36404, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, 36408, + 36408, 36408, 36408, 36408, 36408, 36408, 36408}}; +const char32_t decomposition_data[9102] = { + 0, 32, 32, 776, 97, 32, 772, 50, 51, + 32, 769, 956, 32, 807, 49, 111, 49, 8260, + 52, 49, 8260, 50, 51, 8260, 52, 65, 768, + 65, 769, 65, 770, 65, 771, 65, 776, 65, + 778, 67, 807, 69, 768, 69, 769, 69, 770, + 69, 776, 73, 768, 73, 769, 73, 770, 73, + 776, 78, 771, 79, 768, 79, 769, 79, 770, + 79, 771, 79, 776, 85, 768, 85, 769, 85, + 770, 85, 776, 89, 769, 97, 768, 97, 769, + 97, 770, 97, 771, 97, 776, 97, 778, 99, + 807, 101, 768, 101, 769, 101, 770, 101, 776, + 105, 768, 105, 769, 105, 770, 105, 776, 110, + 771, 111, 768, 111, 769, 111, 770, 111, 771, + 111, 776, 117, 768, 117, 769, 117, 770, 117, + 776, 121, 769, 121, 776, 65, 772, 97, 772, + 65, 774, 97, 774, 65, 808, 97, 808, 67, + 769, 99, 769, 67, 770, 99, 770, 67, 775, + 99, 775, 67, 780, 99, 780, 68, 780, 100, + 780, 69, 772, 101, 772, 69, 774, 101, 774, + 69, 775, 101, 775, 69, 808, 101, 808, 69, + 780, 101, 780, 71, 770, 103, 770, 71, 774, + 103, 774, 71, 775, 103, 775, 71, 807, 103, + 807, 72, 770, 104, 770, 73, 771, 105, 771, + 73, 772, 105, 772, 73, 774, 105, 774, 73, + 808, 105, 808, 73, 775, 73, 74, 105, 106, + 74, 770, 106, 770, 75, 807, 107, 807, 76, + 769, 108, 769, 76, 807, 108, 807, 76, 780, + 108, 780, 76, 183, 108, 183, 78, 769, 110, + 769, 78, 807, 110, 807, 78, 780, 110, 780, + 700, 110, 79, 772, 111, 772, 79, 774, 111, + 774, 79, 779, 111, 779, 82, 769, 114, 769, + 82, 807, 114, 807, 82, 780, 114, 780, 83, + 769, 115, 769, 83, 770, 115, 770, 83, 807, + 115, 807, 83, 780, 115, 780, 84, 807, 116, + 807, 84, 780, 116, 780, 85, 771, 117, 771, + 85, 772, 117, 772, 85, 774, 117, 774, 85, + 778, 117, 778, 85, 779, 117, 779, 85, 808, + 117, 808, 87, 770, 119, 770, 89, 770, 121, + 770, 89, 776, 90, 769, 122, 769, 90, 775, + 122, 775, 90, 780, 122, 780, 115, 79, 795, + 111, 795, 85, 795, 117, 795, 68, 90, 780, + 68, 122, 780, 100, 122, 780, 76, 74, 76, + 106, 108, 106, 78, 74, 78, 106, 110, 106, + 65, 780, 97, 780, 73, 780, 105, 780, 79, + 780, 111, 780, 85, 780, 117, 780, 85, 776, + 772, 117, 776, 772, 85, 776, 769, 117, 776, + 769, 85, 776, 780, 117, 776, 780, 85, 776, + 768, 117, 776, 768, 65, 776, 772, 97, 776, + 772, 65, 775, 772, 97, 775, 772, 198, 772, + 230, 772, 71, 780, 103, 780, 75, 780, 107, + 780, 79, 808, 111, 808, 79, 808, 772, 111, + 808, 772, 439, 780, 658, 780, 106, 780, 68, + 90, 68, 122, 100, 122, 71, 769, 103, 769, + 78, 768, 110, 768, 65, 778, 769, 97, 778, + 769, 198, 769, 230, 769, 216, 769, 248, 769, + 65, 783, 97, 783, 65, 785, 97, 785, 69, + 783, 101, 783, 69, 785, 101, 785, 73, 783, + 105, 783, 73, 785, 105, 785, 79, 783, 111, + 783, 79, 785, 111, 785, 82, 783, 114, 783, + 82, 785, 114, 785, 85, 783, 117, 783, 85, + 785, 117, 785, 83, 806, 115, 806, 84, 806, + 116, 806, 72, 780, 104, 780, 65, 775, 97, + 775, 69, 807, 101, 807, 79, 776, 772, 111, + 776, 772, 79, 771, 772, 111, 771, 772, 79, + 775, 111, 775, 79, 775, 772, 111, 775, 772, + 89, 772, 121, 772, 104, 614, 106, 114, 633, + 635, 641, 119, 121, 32, 774, 32, 775, 32, + 778, 32, 808, 32, 771, 32, 779, 611, 108, + 115, 120, 661, 768, 769, 787, 776, 769, 697, + 32, 837, 59, 32, 769, 168, 769, 913, 769, + 183, 917, 769, 919, 769, 921, 769, 927, 769, + 933, 769, 937, 769, 953, 776, 769, 921, 776, + 933, 776, 945, 769, 949, 769, 951, 769, 953, + 769, 965, 776, 769, 953, 776, 965, 776, 959, + 769, 965, 769, 969, 769, 946, 952, 933, 978, + 769, 978, 776, 966, 960, 954, 961, 962, 920, + 949, 931, 1045, 768, 1045, 776, 1043, 769, 1030, + 776, 1050, 769, 1048, 768, 1059, 774, 1048, 774, + 1080, 774, 1077, 768, 1077, 776, 1075, 769, 1110, + 776, 1082, 769, 1080, 768, 1091, 774, 1140, 783, + 1141, 783, 1046, 774, 1078, 774, 1040, 774, 1072, + 774, 1040, 776, 1072, 776, 1045, 774, 1077, 774, + 1240, 776, 1241, 776, 1046, 776, 1078, 776, 1047, + 776, 1079, 776, 1048, 772, 1080, 772, 1048, 776, + 1080, 776, 1054, 776, 1086, 776, 1256, 776, 1257, + 776, 1069, 776, 1101, 776, 1059, 772, 1091, 772, + 1059, 776, 1091, 776, 1059, 779, 1091, 779, 1063, + 776, 1095, 776, 1067, 776, 1099, 776, 1381, 1410, + 1575, 1619, 1575, 1620, 1608, 1620, 1575, 1621, 1610, + 1620, 1575, 1652, 1608, 1652, 1735, 1652, 1610, 1652, + 1749, 1620, 1729, 1620, 1746, 1620, 2344, 2364, 2352, + 2364, 2355, 2364, 2325, 2364, 2326, 2364, 2327, 2364, + 2332, 2364, 2337, 2364, 2338, 2364, 2347, 2364, 2351, + 2364, 2503, 2494, 2503, 2519, 2465, 2492, 2466, 2492, + 2479, 2492, 2610, 2620, 2616, 2620, 2582, 2620, 2583, + 2620, 2588, 2620, 2603, 2620, 2887, 2902, 2887, 2878, + 2887, 2903, 2849, 2876, 2850, 2876, 2962, 3031, 3014, + 3006, 3015, 3006, 3014, 3031, 3142, 3158, 3263, 3285, + 3270, 3285, 3270, 3286, 3270, 3266, 3270, 3266, 3285, + 3398, 3390, 3399, 3390, 3398, 3415, 3545, 3530, 3545, + 3535, 3545, 3535, 3530, 3545, 3551, 3661, 3634, 3789, + 3762, 3755, 3737, 3755, 3745, 3851, 3906, 4023, 3916, + 4023, 3921, 4023, 3926, 4023, 3931, 4023, 3904, 4021, + 3953, 3954, 3953, 3956, 4018, 3968, 4018, 3953, 3968, + 4019, 3968, 4019, 3953, 3968, 3953, 3968, 3986, 4023, + 3996, 4023, 4001, 4023, 4006, 4023, 4011, 4023, 3984, + 4021, 4133, 4142, 4316, 6917, 6965, 6919, 6965, 6921, + 6965, 6923, 6965, 6925, 6965, 6929, 6965, 6970, 6965, + 6972, 6965, 6974, 6965, 6975, 6965, 6978, 6965, 65, + 198, 66, 68, 69, 398, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 546, 80, 82, 84, + 85, 87, 97, 592, 593, 7426, 98, 100, 101, + 601, 603, 604, 103, 107, 109, 331, 111, 596, + 7446, 7447, 112, 116, 117, 7453, 623, 118, 7461, + 946, 947, 948, 966, 967, 105, 114, 117, 118, + 946, 947, 961, 966, 967, 1085, 594, 99, 597, + 240, 604, 102, 607, 609, 613, 616, 617, 618, + 7547, 669, 621, 7557, 671, 625, 624, 626, 627, + 628, 629, 632, 642, 643, 427, 649, 650, 7452, + 651, 652, 122, 656, 657, 658, 952, 65, 805, + 97, 805, 66, 775, 98, 775, 66, 803, 98, + 803, 66, 817, 98, 817, 67, 807, 769, 99, + 807, 769, 68, 775, 100, 775, 68, 803, 100, + 803, 68, 817, 100, 817, 68, 807, 100, 807, + 68, 813, 100, 813, 69, 772, 768, 101, 772, + 768, 69, 772, 769, 101, 772, 769, 69, 813, + 101, 813, 69, 816, 101, 816, 69, 807, 774, + 101, 807, 774, 70, 775, 102, 775, 71, 772, + 103, 772, 72, 775, 104, 775, 72, 803, 104, + 803, 72, 776, 104, 776, 72, 807, 104, 807, + 72, 814, 104, 814, 73, 816, 105, 816, 73, + 776, 769, 105, 776, 769, 75, 769, 107, 769, + 75, 803, 107, 803, 75, 817, 107, 817, 76, + 803, 108, 803, 76, 803, 772, 108, 803, 772, + 76, 817, 108, 817, 76, 813, 108, 813, 77, + 769, 109, 769, 77, 775, 109, 775, 77, 803, + 109, 803, 78, 775, 110, 775, 78, 803, 110, + 803, 78, 817, 110, 817, 78, 813, 110, 813, + 79, 771, 769, 111, 771, 769, 79, 771, 776, + 111, 771, 776, 79, 772, 768, 111, 772, 768, + 79, 772, 769, 111, 772, 769, 80, 769, 112, + 769, 80, 775, 112, 775, 82, 775, 114, 775, + 82, 803, 114, 803, 82, 803, 772, 114, 803, + 772, 82, 817, 114, 817, 83, 775, 115, 775, + 83, 803, 115, 803, 83, 769, 775, 115, 769, + 775, 83, 780, 775, 115, 780, 775, 83, 803, + 775, 115, 803, 775, 84, 775, 116, 775, 84, + 803, 116, 803, 84, 817, 116, 817, 84, 813, + 116, 813, 85, 804, 117, 804, 85, 816, 117, + 816, 85, 813, 117, 813, 85, 771, 769, 117, + 771, 769, 85, 772, 776, 117, 772, 776, 86, + 771, 118, 771, 86, 803, 118, 803, 87, 768, + 119, 768, 87, 769, 119, 769, 87, 776, 119, + 776, 87, 775, 119, 775, 87, 803, 119, 803, + 88, 775, 120, 775, 88, 776, 120, 776, 89, + 775, 121, 775, 90, 770, 122, 770, 90, 803, + 122, 803, 90, 817, 122, 817, 104, 817, 116, + 776, 119, 778, 121, 778, 97, 702, 383, 775, + 65, 803, 97, 803, 65, 777, 97, 777, 65, + 770, 769, 97, 770, 769, 65, 770, 768, 97, + 770, 768, 65, 770, 777, 97, 770, 777, 65, + 770, 771, 97, 770, 771, 65, 803, 770, 97, + 803, 770, 65, 774, 769, 97, 774, 769, 65, + 774, 768, 97, 774, 768, 65, 774, 777, 97, + 774, 777, 65, 774, 771, 97, 774, 771, 65, + 803, 774, 97, 803, 774, 69, 803, 101, 803, + 69, 777, 101, 777, 69, 771, 101, 771, 69, + 770, 769, 101, 770, 769, 69, 770, 768, 101, + 770, 768, 69, 770, 777, 101, 770, 777, 69, + 770, 771, 101, 770, 771, 69, 803, 770, 101, + 803, 770, 73, 777, 105, 777, 73, 803, 105, + 803, 79, 803, 111, 803, 79, 777, 111, 777, + 79, 770, 769, 111, 770, 769, 79, 770, 768, + 111, 770, 768, 79, 770, 777, 111, 770, 777, + 79, 770, 771, 111, 770, 771, 79, 803, 770, + 111, 803, 770, 79, 795, 769, 111, 795, 769, + 79, 795, 768, 111, 795, 768, 79, 795, 777, + 111, 795, 777, 79, 795, 771, 111, 795, 771, + 79, 795, 803, 111, 795, 803, 85, 803, 117, + 803, 85, 777, 117, 777, 85, 795, 769, 117, + 795, 769, 85, 795, 768, 117, 795, 768, 85, + 795, 777, 117, 795, 777, 85, 795, 771, 117, + 795, 771, 85, 795, 803, 117, 795, 803, 89, + 768, 121, 768, 89, 803, 121, 803, 89, 777, + 121, 777, 89, 771, 121, 771, 945, 787, 945, + 788, 945, 787, 768, 945, 788, 768, 945, 787, + 769, 945, 788, 769, 945, 787, 834, 945, 788, + 834, 913, 787, 913, 788, 913, 787, 768, 913, + 788, 768, 913, 787, 769, 913, 788, 769, 913, + 787, 834, 913, 788, 834, 949, 787, 949, 788, + 949, 787, 768, 949, 788, 768, 949, 787, 769, + 949, 788, 769, 917, 787, 917, 788, 917, 787, + 768, 917, 788, 768, 917, 787, 769, 917, 788, + 769, 951, 787, 951, 788, 951, 787, 768, 951, + 788, 768, 951, 787, 769, 951, 788, 769, 951, + 787, 834, 951, 788, 834, 919, 787, 919, 788, + 919, 787, 768, 919, 788, 768, 919, 787, 769, + 919, 788, 769, 919, 787, 834, 919, 788, 834, + 953, 787, 953, 788, 953, 787, 768, 953, 788, + 768, 953, 787, 769, 953, 788, 769, 953, 787, + 834, 953, 788, 834, 921, 787, 921, 788, 921, + 787, 768, 921, 788, 768, 921, 787, 769, 921, + 788, 769, 921, 787, 834, 921, 788, 834, 959, + 787, 959, 788, 959, 787, 768, 959, 788, 768, + 959, 787, 769, 959, 788, 769, 927, 787, 927, + 788, 927, 787, 768, 927, 788, 768, 927, 787, + 769, 927, 788, 769, 965, 787, 965, 788, 965, + 787, 768, 965, 788, 768, 965, 787, 769, 965, + 788, 769, 965, 787, 834, 965, 788, 834, 933, + 788, 933, 788, 768, 933, 788, 769, 933, 788, + 834, 969, 787, 969, 788, 969, 787, 768, 969, + 788, 768, 969, 787, 769, 969, 788, 769, 969, + 787, 834, 969, 788, 834, 937, 787, 937, 788, + 937, 787, 768, 937, 788, 768, 937, 787, 769, + 937, 788, 769, 937, 787, 834, 937, 788, 834, + 945, 768, 945, 769, 949, 768, 949, 769, 951, + 768, 951, 769, 953, 768, 953, 769, 959, 768, + 959, 769, 965, 768, 965, 769, 969, 768, 969, + 769, 945, 787, 837, 945, 788, 837, 945, 787, + 768, 837, 945, 788, 768, 837, 945, 787, 769, + 837, 945, 788, 769, 837, 945, 787, 834, 837, + 945, 788, 834, 837, 913, 787, 837, 913, 788, + 837, 913, 787, 768, 837, 913, 788, 768, 837, + 913, 787, 769, 837, 913, 788, 769, 837, 913, + 787, 834, 837, 913, 788, 834, 837, 951, 787, + 837, 951, 788, 837, 951, 787, 768, 837, 951, + 788, 768, 837, 951, 787, 769, 837, 951, 788, + 769, 837, 951, 787, 834, 837, 951, 788, 834, + 837, 919, 787, 837, 919, 788, 837, 919, 787, + 768, 837, 919, 788, 768, 837, 919, 787, 769, + 837, 919, 788, 769, 837, 919, 787, 834, 837, + 919, 788, 834, 837, 969, 787, 837, 969, 788, + 837, 969, 787, 768, 837, 969, 788, 768, 837, + 969, 787, 769, 837, 969, 788, 769, 837, 969, + 787, 834, 837, 969, 788, 834, 837, 937, 787, + 837, 937, 788, 837, 937, 787, 768, 837, 937, + 788, 768, 837, 937, 787, 769, 837, 937, 788, + 769, 837, 937, 787, 834, 837, 937, 788, 834, + 837, 945, 774, 945, 772, 945, 768, 837, 945, + 837, 945, 769, 837, 945, 834, 945, 834, 837, + 913, 774, 913, 772, 913, 768, 913, 769, 913, + 837, 32, 787, 953, 32, 787, 32, 834, 168, + 834, 951, 768, 837, 951, 837, 951, 769, 837, + 951, 834, 951, 834, 837, 917, 768, 917, 769, + 919, 768, 919, 769, 919, 837, 8127, 768, 8127, + 769, 8127, 834, 953, 774, 953, 772, 953, 776, + 768, 953, 776, 769, 953, 834, 953, 776, 834, + 921, 774, 921, 772, 921, 768, 921, 769, 8190, + 768, 8190, 769, 8190, 834, 965, 774, 965, 772, + 965, 776, 768, 965, 776, 769, 961, 787, 961, + 788, 965, 834, 965, 776, 834, 933, 774, 933, + 772, 933, 768, 933, 769, 929, 788, 168, 768, + 168, 769, 96, 969, 768, 837, 969, 837, 969, + 769, 837, 969, 834, 969, 834, 837, 927, 768, + 927, 769, 937, 768, 937, 769, 937, 837, 180, + 32, 788, 8194, 8195, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 8208, 32, 819, 46, 46, + 46, 46, 46, 46, 32, 8242, 8242, 8242, 8242, + 8242, 8245, 8245, 8245, 8245, 8245, 33, 33, 32, + 773, 63, 63, 63, 33, 33, 63, 8242, 8242, + 8242, 8242, 32, 48, 105, 52, 53, 54, 55, + 56, 57, 43, 8722, 61, 40, 41, 110, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, + 43, 8722, 61, 40, 41, 97, 101, 111, 120, + 601, 104, 107, 108, 109, 110, 112, 115, 116, + 82, 115, 97, 47, 99, 97, 47, 115, 67, + 176, 67, 99, 47, 111, 99, 47, 117, 400, + 176, 70, 103, 72, 72, 72, 104, 295, 73, + 73, 76, 108, 78, 78, 111, 80, 81, 82, + 82, 82, 83, 77, 84, 69, 76, 84, 77, + 90, 937, 90, 75, 65, 778, 66, 67, 101, + 69, 70, 77, 111, 1488, 1489, 1490, 1491, 105, + 70, 65, 88, 960, 947, 915, 928, 8721, 68, + 100, 101, 105, 106, 49, 8260, 55, 49, 8260, + 57, 49, 8260, 49, 48, 49, 8260, 51, 50, + 8260, 51, 49, 8260, 53, 50, 8260, 53, 51, + 8260, 53, 52, 8260, 53, 49, 8260, 54, 53, + 8260, 54, 49, 8260, 56, 51, 8260, 56, 53, + 8260, 56, 55, 8260, 56, 49, 8260, 73, 73, + 73, 73, 73, 73, 73, 86, 86, 86, 73, + 86, 73, 73, 86, 73, 73, 73, 73, 88, + 88, 88, 73, 88, 73, 73, 76, 67, 68, + 77, 105, 105, 105, 105, 105, 105, 105, 118, + 118, 118, 105, 118, 105, 105, 118, 105, 105, + 105, 105, 120, 120, 120, 105, 120, 105, 105, + 108, 99, 100, 109, 48, 8260, 51, 8592, 824, + 8594, 824, 8596, 824, 8656, 824, 8660, 824, 8658, + 824, 8707, 824, 8712, 824, 8715, 824, 8739, 824, + 8741, 824, 8747, 8747, 8747, 8747, 8747, 8750, 8750, + 8750, 8750, 8750, 8764, 824, 8771, 824, 8773, 824, + 8776, 824, 61, 824, 8801, 824, 8781, 824, 60, + 824, 62, 824, 8804, 824, 8805, 824, 8818, 824, + 8819, 824, 8822, 824, 8823, 824, 8826, 824, 8827, + 824, 8834, 824, 8835, 824, 8838, 824, 8839, 824, + 8866, 824, 8872, 824, 8873, 824, 8875, 824, 8828, + 824, 8829, 824, 8849, 824, 8850, 824, 8882, 824, + 8883, 824, 8884, 824, 8885, 824, 12296, 12297, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 49, + 48, 49, 49, 49, 50, 49, 51, 49, 52, + 49, 53, 49, 54, 49, 55, 49, 56, 49, + 57, 50, 48, 40, 49, 41, 40, 50, 41, + 40, 51, 41, 40, 52, 41, 40, 53, 41, + 40, 54, 41, 40, 55, 41, 40, 56, 41, + 40, 57, 41, 40, 49, 48, 41, 40, 49, + 49, 41, 40, 49, 50, 41, 40, 49, 51, + 41, 40, 49, 52, 41, 40, 49, 53, 41, + 40, 49, 54, 41, 40, 49, 55, 41, 40, + 49, 56, 41, 40, 49, 57, 41, 40, 50, + 48, 41, 49, 46, 50, 46, 51, 46, 52, + 46, 53, 46, 54, 46, 55, 46, 56, 46, + 57, 46, 49, 48, 46, 49, 49, 46, 49, + 50, 46, 49, 51, 46, 49, 52, 46, 49, + 53, 46, 49, 54, 46, 49, 55, 46, 49, + 56, 46, 49, 57, 46, 50, 48, 46, 40, + 97, 41, 40, 98, 41, 40, 99, 41, 40, + 100, 41, 40, 101, 41, 40, 102, 41, 40, + 103, 41, 40, 104, 41, 40, 105, 41, 40, + 106, 41, 40, 107, 41, 40, 108, 41, 40, + 109, 41, 40, 110, 41, 40, 111, 41, 40, + 112, 41, 40, 113, 41, 40, 114, 41, 40, + 115, 41, 40, 116, 41, 40, 117, 41, 40, + 118, 41, 40, 119, 41, 40, 120, 41, 40, + 121, 41, 40, 122, 41, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 48, 8747, 8747, 8747, 8747, 58, + 58, 61, 61, 61, 61, 61, 61, 10973, 824, + 106, 86, 11617, 27597, 40863, 19968, 20008, 20022, 20031, + 20057, 20101, 20108, 20128, 20154, 20799, 20837, 20843, 20866, + 20886, 20907, 20960, 20981, 20992, 21147, 21241, 21269, 21274, + 21304, 21313, 21340, 21353, 21378, 21430, 21448, 21475, 22231, + 22303, 22763, 22786, 22794, 22805, 22823, 22899, 23376, 23424, + 23544, 23567, 23586, 23608, 23662, 23665, 24027, 24037, 24049, + 24062, 24178, 24186, 24191, 24308, 24318, 24331, 24339, 24400, + 24417, 24435, 24515, 25096, 25142, 25163, 25903, 25908, 25991, + 26007, 26020, 26041, 26080, 26085, 26352, 26376, 26408, 27424, + 27490, 27513, 27571, 27595, 27604, 27611, 27663, 27668, 27700, + 28779, 29226, 29238, 29243, 29247, 29255, 29273, 29275, 29356, + 29572, 29577, 29916, 29926, 29976, 29983, 29992, 30000, 30091, + 30098, 30326, 30333, 30382, 30399, 30446, 30683, 30690, 30707, + 31034, 31160, 31166, 31348, 31435, 31481, 31859, 31992, 32566, + 32593, 32650, 32701, 32769, 32780, 32786, 32819, 32895, 32905, + 33251, 33258, 33267, 33276, 33292, 33307, 33311, 33390, 33394, + 33400, 34381, 34411, 34880, 34892, 34915, 35198, 35211, 35282, + 35328, 35895, 35910, 35925, 35960, 35997, 36196, 36208, 36275, + 36523, 36554, 36763, 36784, 36789, 37009, 37193, 37318, 37324, + 37329, 38263, 38272, 38428, 38582, 38585, 38632, 38737, 38750, + 38754, 38761, 38859, 38893, 38899, 38913, 39080, 39131, 39135, + 39318, 39321, 39340, 39592, 39640, 39647, 39717, 39727, 39730, + 39740, 39770, 40165, 40565, 40575, 40613, 40635, 40643, 40653, + 40657, 40697, 40701, 40718, 40723, 40736, 40763, 40778, 40786, + 40845, 40860, 40864, 32, 12306, 21313, 21316, 21317, 12363, + 12441, 12365, 12441, 12367, 12441, 12369, 12441, 12371, 12441, + 12373, 12441, 12375, 12441, 12377, 12441, 12379, 12441, 12381, + 12441, 12383, 12441, 12385, 12441, 12388, 12441, 12390, 12441, + 12392, 12441, 12399, 12441, 12399, 12442, 12402, 12441, 12402, + 12442, 12405, 12441, 12405, 12442, 12408, 12441, 12408, 12442, + 12411, 12441, 12411, 12442, 12358, 12441, 32, 12441, 32, + 12442, 12445, 12441, 12424, 12426, 12459, 12441, 12461, 12441, + 12463, 12441, 12465, 12441, 12467, 12441, 12469, 12441, 12471, + 12441, 12473, 12441, 12475, 12441, 12477, 12441, 12479, 12441, + 12481, 12441, 12484, 12441, 12486, 12441, 12488, 12441, 12495, + 12441, 12495, 12442, 12498, 12441, 12498, 12442, 12501, 12441, + 12501, 12442, 12504, 12441, 12504, 12442, 12507, 12441, 12507, + 12442, 12454, 12441, 12527, 12441, 12528, 12441, 12529, 12441, + 12530, 12441, 12541, 12441, 12467, 12488, 4352, 4353, 4522, + 4354, 4524, 4525, 4355, 4356, 4357, 4528, 4529, 4530, + 4531, 4532, 4533, 4378, 4358, 4359, 4360, 4385, 4361, + 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, + 4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457, + 4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, 4466, + 4467, 4468, 4469, 4448, 4372, 4373, 4551, 4552, 4556, + 4558, 4563, 4567, 4569, 4380, 4573, 4575, 4381, 4382, + 4384, 4386, 4387, 4391, 4393, 4395, 4396, 4397, 4398, + 4399, 4402, 4406, 4416, 4423, 4428, 4593, 4594, 4439, + 4440, 4441, 4484, 4485, 4488, 4497, 4498, 4500, 4510, + 4513, 19968, 20108, 19977, 22235, 19978, 20013, 19979, 30002, + 20057, 19993, 19969, 22825, 22320, 20154, 40, 4352, 41, + 40, 4354, 41, 40, 4355, 41, 40, 4357, 41, + 40, 4358, 41, 40, 4359, 41, 40, 4361, 41, + 40, 4363, 41, 40, 4364, 41, 40, 4366, 41, + 40, 4367, 41, 40, 4368, 41, 40, 4369, 41, + 40, 4370, 41, 40, 4352, 4449, 41, 40, 4354, + 4449, 41, 40, 4355, 4449, 41, 40, 4357, 4449, + 41, 40, 4358, 4449, 41, 40, 4359, 4449, 41, + 40, 4361, 4449, 41, 40, 4363, 4449, 41, 40, + 4364, 4449, 41, 40, 4366, 4449, 41, 40, 4367, + 4449, 41, 40, 4368, 4449, 41, 40, 4369, 4449, + 41, 40, 4370, 4449, 41, 40, 4364, 4462, 41, + 40, 4363, 4457, 4364, 4453, 4523, 41, 40, 4363, + 4457, 4370, 4462, 41, 40, 19968, 41, 40, 20108, + 41, 40, 19977, 41, 40, 22235, 41, 40, 20116, + 41, 40, 20845, 41, 40, 19971, 41, 40, 20843, + 41, 40, 20061, 41, 40, 21313, 41, 40, 26376, + 41, 40, 28779, 41, 40, 27700, 41, 40, 26408, + 41, 40, 37329, 41, 40, 22303, 41, 40, 26085, + 41, 40, 26666, 41, 40, 26377, 41, 40, 31038, + 41, 40, 21517, 41, 40, 29305, 41, 40, 36001, + 41, 40, 31069, 41, 40, 21172, 41, 40, 20195, + 41, 40, 21628, 41, 40, 23398, 41, 40, 30435, + 41, 40, 20225, 41, 40, 36039, 41, 40, 21332, + 41, 40, 31085, 41, 40, 20241, 41, 40, 33258, + 41, 40, 33267, 41, 21839, 24188, 25991, 31631, 80, + 84, 69, 50, 49, 50, 50, 50, 51, 50, + 52, 50, 53, 50, 54, 50, 55, 50, 56, + 50, 57, 51, 48, 51, 49, 51, 50, 51, + 51, 51, 52, 51, 53, 4352, 4354, 4355, 4357, + 4358, 4359, 4361, 4363, 4364, 4366, 4367, 4368, 4369, + 4370, 4352, 4449, 4354, 4449, 4355, 4449, 4357, 4449, + 4358, 4449, 4359, 4449, 4361, 4449, 4363, 4449, 4364, + 4449, 4366, 4449, 4367, 4449, 4368, 4449, 4369, 4449, + 4370, 4449, 4366, 4449, 4535, 4352, 4457, 4364, 4462, + 4363, 4468, 4363, 4462, 19968, 20108, 19977, 22235, 20116, + 20845, 19971, 20843, 20061, 21313, 26376, 28779, 27700, 26408, + 37329, 22303, 26085, 26666, 26377, 31038, 21517, 29305, 36001, + 31069, 21172, 31192, 30007, 22899, 36969, 20778, 21360, 27880, + 38917, 20241, 20889, 27491, 19978, 20013, 19979, 24038, 21491, + 21307, 23447, 23398, 30435, 20225, 36039, 21332, 22812, 51, + 54, 51, 55, 51, 56, 51, 57, 52, 48, + 52, 49, 52, 50, 52, 51, 52, 52, 52, + 53, 52, 54, 52, 55, 52, 56, 52, 57, + 53, 48, 49, 26376, 50, 26376, 51, 26376, 52, + 26376, 53, 26376, 54, 26376, 55, 26376, 56, 26376, + 57, 26376, 49, 48, 26376, 49, 49, 26376, 49, + 50, 26376, 72, 103, 101, 114, 103, 101, 86, + 76, 84, 68, 12450, 12452, 12454, 12456, 12458, 12459, + 12461, 12463, 12465, 12467, 12469, 12471, 12473, 12475, 12477, + 12479, 12481, 12484, 12486, 12488, 12490, 12491, 12492, 12493, + 12494, 12495, 12498, 12501, 12504, 12507, 12510, 12511, 12512, + 12513, 12514, 12516, 12518, 12520, 12521, 12522, 12523, 12524, + 12525, 12527, 12528, 12529, 12530, 20196, 21644, 12450, 12495, + 12442, 12540, 12488, 12450, 12523, 12501, 12449, 12450, 12531, + 12504, 12442, 12450, 12450, 12540, 12523, 12452, 12491, 12531, + 12463, 12441, 12452, 12531, 12481, 12454, 12457, 12531, 12456, + 12473, 12463, 12540, 12488, 12441, 12456, 12540, 12459, 12540, + 12458, 12531, 12473, 12458, 12540, 12512, 12459, 12452, 12522, + 12459, 12521, 12483, 12488, 12459, 12525, 12522, 12540, 12459, + 12441, 12525, 12531, 12459, 12441, 12531, 12510, 12461, 12441, + 12459, 12441, 12461, 12441, 12491, 12540, 12461, 12517, 12522, + 12540, 12461, 12441, 12523, 12479, 12441, 12540, 12461, 12525, + 12461, 12525, 12463, 12441, 12521, 12512, 12461, 12525, 12513, + 12540, 12488, 12523, 12461, 12525, 12527, 12483, 12488, 12463, + 12441, 12521, 12512, 12463, 12441, 12521, 12512, 12488, 12531, + 12463, 12523, 12475, 12441, 12452, 12525, 12463, 12525, 12540, + 12493, 12465, 12540, 12473, 12467, 12523, 12490, 12467, 12540, + 12507, 12442, 12469, 12452, 12463, 12523, 12469, 12531, 12481, + 12540, 12512, 12471, 12522, 12531, 12463, 12441, 12475, 12531, + 12481, 12475, 12531, 12488, 12479, 12441, 12540, 12473, 12486, + 12441, 12471, 12488, 12441, 12523, 12488, 12531, 12490, 12494, + 12494, 12483, 12488, 12495, 12452, 12484, 12495, 12442, 12540, + 12475, 12531, 12488, 12495, 12442, 12540, 12484, 12495, 12441, + 12540, 12524, 12523, 12498, 12442, 12450, 12473, 12488, 12523, + 12498, 12442, 12463, 12523, 12498, 12442, 12467, 12498, 12441, + 12523, 12501, 12449, 12521, 12483, 12488, 12441, 12501, 12451, + 12540, 12488, 12501, 12441, 12483, 12471, 12455, 12523, 12501, + 12521, 12531, 12504, 12463, 12479, 12540, 12523, 12504, 12442, + 12477, 12504, 12442, 12491, 12498, 12504, 12523, 12484, 12504, + 12442, 12531, 12473, 12504, 12442, 12540, 12471, 12441, 12504, + 12441, 12540, 12479, 12507, 12442, 12452, 12531, 12488, 12507, + 12441, 12523, 12488, 12507, 12531, 12507, 12442, 12531, 12488, + 12441, 12507, 12540, 12523, 12507, 12540, 12531, 12510, 12452, + 12463, 12525, 12510, 12452, 12523, 12510, 12483, 12495, 12510, + 12523, 12463, 12510, 12531, 12471, 12519, 12531, 12511, 12463, + 12525, 12531, 12511, 12522, 12511, 12522, 12495, 12441, 12540, + 12523, 12513, 12459, 12441, 12513, 12459, 12441, 12488, 12531, + 12513, 12540, 12488, 12523, 12516, 12540, 12488, 12441, 12516, + 12540, 12523, 12518, 12450, 12531, 12522, 12483, 12488, 12523, + 12522, 12521, 12523, 12498, 12442, 12540, 12523, 12540, 12501, + 12441, 12523, 12524, 12512, 12524, 12531, 12488, 12465, 12441, + 12531, 12527, 12483, 12488, 48, 28857, 49, 28857, 50, + 28857, 51, 28857, 52, 28857, 53, 28857, 54, 28857, + 55, 28857, 56, 28857, 57, 28857, 49, 48, 28857, + 49, 49, 28857, 49, 50, 28857, 49, 51, 28857, + 49, 52, 28857, 49, 53, 28857, 49, 54, 28857, + 49, 55, 28857, 49, 56, 28857, 49, 57, 28857, + 50, 48, 28857, 50, 49, 28857, 50, 50, 28857, + 50, 51, 28857, 50, 52, 28857, 104, 80, 97, + 100, 97, 65, 85, 98, 97, 114, 111, 86, + 112, 99, 100, 109, 100, 109, 50, 100, 109, + 51, 73, 85, 24179, 25104, 26157, 21644, 22823, 27491, + 26126, 27835, 26666, 24335, 20250, 31038, 112, 65, 110, + 65, 956, 65, 109, 65, 107, 65, 75, 66, + 77, 66, 71, 66, 99, 97, 108, 107, 99, + 97, 108, 112, 70, 110, 70, 956, 70, 956, + 103, 109, 103, 107, 103, 72, 122, 107, 72, + 122, 77, 72, 122, 71, 72, 122, 84, 72, + 122, 956, 108, 109, 108, 100, 108, 107, 108, + 102, 109, 110, 109, 956, 109, 109, 109, 99, + 109, 107, 109, 109, 109, 50, 99, 109, 50, + 109, 50, 107, 109, 50, 109, 109, 51, 99, + 109, 51, 109, 51, 107, 109, 51, 109, 8725, + 115, 109, 8725, 115, 50, 80, 97, 107, 80, + 97, 77, 80, 97, 71, 80, 97, 114, 97, + 100, 114, 97, 100, 8725, 115, 114, 97, 100, + 8725, 115, 50, 112, 115, 110, 115, 956, 115, + 109, 115, 112, 86, 110, 86, 956, 86, 109, + 86, 107, 86, 77, 86, 112, 87, 110, 87, + 956, 87, 109, 87, 107, 87, 77, 87, 107, + 937, 77, 937, 97, 46, 109, 46, 66, 113, + 99, 99, 99, 100, 67, 8725, 107, 103, 67, + 111, 46, 100, 66, 71, 121, 104, 97, 72, + 80, 105, 110, 75, 75, 75, 77, 107, 116, + 108, 109, 108, 110, 108, 111, 103, 108, 120, + 109, 98, 109, 105, 108, 109, 111, 108, 80, + 72, 112, 46, 109, 46, 80, 80, 77, 80, + 82, 115, 114, 83, 118, 87, 98, 86, 8725, + 109, 65, 8725, 109, 49, 26085, 50, 26085, 51, + 26085, 52, 26085, 53, 26085, 54, 26085, 55, 26085, + 56, 26085, 57, 26085, 49, 48, 26085, 49, 49, + 26085, 49, 50, 26085, 49, 51, 26085, 49, 52, + 26085, 49, 53, 26085, 49, 54, 26085, 49, 55, + 26085, 49, 56, 26085, 49, 57, 26085, 50, 48, + 26085, 50, 49, 26085, 50, 50, 26085, 50, 51, + 26085, 50, 52, 26085, 50, 53, 26085, 50, 54, + 26085, 50, 55, 26085, 50, 56, 26085, 50, 57, + 26085, 51, 48, 26085, 51, 49, 26085, 103, 97, + 108, 1098, 1100, 42863, 67, 70, 81, 294, 339, + 42791, 43831, 619, 43858, 653, 35912, 26356, 36554, 36040, + 28369, 20018, 21477, 40860, 40860, 22865, 37329, 21895, 22856, + 25078, 30313, 32645, 34367, 34746, 35064, 37007, 27138, 27931, + 28889, 29662, 33853, 37226, 39409, 20098, 21365, 27396, 29211, + 34349, 40478, 23888, 28651, 34253, 35172, 25289, 33240, 34847, + 24266, 26391, 28010, 29436, 37070, 20358, 20919, 21214, 25796, + 27347, 29200, 30439, 32769, 34310, 34396, 36335, 38706, 39791, + 40442, 30860, 31103, 32160, 33737, 37636, 40575, 35542, 22751, + 24324, 31840, 32894, 29282, 30922, 36034, 38647, 22744, 23650, + 27155, 28122, 28431, 32047, 32311, 38475, 21202, 32907, 20956, + 20940, 31260, 32190, 33777, 38517, 35712, 25295, 27138, 35582, + 20025, 23527, 24594, 29575, 30064, 21271, 30971, 20415, 24489, + 19981, 27852, 25976, 32034, 21443, 22622, 30465, 33865, 35498, + 27578, 36784, 27784, 25342, 33509, 25504, 30053, 20142, 20841, + 20937, 26753, 31975, 33391, 35538, 37327, 21237, 21570, 22899, + 24300, 26053, 28670, 31018, 38317, 39530, 40599, 40654, 21147, + 26310, 27511, 36706, 24180, 24976, 25088, 25754, 28451, 29001, + 29833, 31178, 32244, 32879, 36646, 34030, 36899, 37706, 21015, + 21155, 21693, 28872, 35010, 35498, 24265, 24565, 25467, 27566, + 31806, 29557, 20196, 22265, 23527, 23994, 24604, 29618, 29801, + 32666, 32838, 37428, 38646, 38728, 38936, 20363, 31150, 37300, + 38584, 24801, 20102, 20698, 23534, 23615, 26009, 27138, 29134, + 30274, 34044, 36988, 40845, 26248, 38446, 21129, 26491, 26611, + 27969, 28316, 29705, 30041, 30827, 32016, 39006, 20845, 25134, + 38520, 20523, 23833, 28138, 36650, 24459, 24900, 26647, 29575, + 38534, 21033, 21519, 23653, 26131, 26446, 26792, 27877, 29702, + 30178, 32633, 35023, 35041, 37324, 38626, 21311, 28346, 21533, + 29136, 29848, 34298, 38563, 40023, 40607, 26519, 28107, 33256, + 31435, 31520, 31890, 29376, 28825, 35672, 20160, 33590, 21050, + 20999, 24230, 25299, 31958, 23429, 27934, 26292, 36667, 34892, + 38477, 35211, 24275, 20800, 21952, 22618, 26228, 20958, 29482, + 30410, 31036, 31070, 31077, 31119, 38742, 31934, 32701, 34322, + 35576, 36920, 37117, 39151, 39164, 39208, 40372, 37086, 38583, + 20398, 20711, 20813, 21193, 21220, 21329, 21917, 22022, 22120, + 22592, 22696, 23652, 23662, 24724, 24936, 24974, 25074, 25935, + 26082, 26257, 26757, 28023, 28186, 28450, 29038, 29227, 29730, + 30865, 31038, 31049, 31048, 31056, 31062, 31069, 31117, 31118, + 31296, 31361, 31680, 32244, 32265, 32321, 32626, 32773, 33261, + 33401, 33401, 33879, 35088, 35222, 35585, 35641, 36051, 36104, + 36790, 36920, 38627, 38911, 38971, 24693, 148206, 33304, 20006, + 20917, 20840, 20352, 20805, 20864, 21191, 21242, 21917, 21845, + 21913, 21986, 22618, 22707, 22852, 22868, 23138, 23336, 24274, + 24281, 24425, 24493, 24792, 24910, 24840, 24974, 24928, 25074, + 25140, 25540, 25628, 25682, 25942, 26228, 26391, 26395, 26454, + 27513, 27578, 27969, 28379, 28363, 28450, 28702, 29038, 30631, + 29237, 29359, 29482, 29809, 29958, 30011, 30237, 30239, 30410, + 30427, 30452, 30538, 30528, 30924, 31409, 31680, 31867, 32091, + 32244, 32574, 32773, 33618, 33775, 34681, 35137, 35206, 35222, + 35519, 35576, 35531, 35585, 35582, 35565, 35641, 35722, 36104, + 36664, 36978, 37273, 37494, 38524, 38627, 38742, 38875, 38911, + 38923, 38971, 39698, 40860, 141386, 141380, 144341, 15261, 16408, + 16441, 152137, 154832, 163539, 40771, 40846, 102, 102, 102, + 105, 102, 108, 102, 102, 105, 102, 102, 108, + 115, 116, 115, 116, 1396, 1398, 1396, 1381, 1396, + 1387, 1406, 1398, 1396, 1389, 1497, 1460, 1522, 1463, + 1506, 1488, 1491, 1492, 1499, 1500, 1501, 1512, 1514, + 43, 1513, 1473, 1513, 1474, 1513, 1468, 1473, 1513, + 1468, 1474, 1488, 1463, 1488, 1464, 1488, 1468, 1489, + 1468, 1490, 1468, 1491, 1468, 1492, 1468, 1493, 1468, + 1494, 1468, 1496, 1468, 1497, 1468, 1498, 1468, 1499, + 1468, 1500, 1468, 1502, 1468, 1504, 1468, 1505, 1468, + 1507, 1468, 1508, 1468, 1510, 1468, 1511, 1468, 1512, + 1468, 1513, 1468, 1514, 1468, 1493, 1465, 1489, 1471, + 1499, 1471, 1508, 1471, 1488, 1500, 1649, 1649, 1659, + 1659, 1659, 1659, 1662, 1662, 1662, 1662, 1664, 1664, + 1664, 1664, 1658, 1658, 1658, 1658, 1663, 1663, 1663, + 1663, 1657, 1657, 1657, 1657, 1700, 1700, 1700, 1700, + 1702, 1702, 1702, 1702, 1668, 1668, 1668, 1668, 1667, + 1667, 1667, 1667, 1670, 1670, 1670, 1670, 1671, 1671, + 1671, 1671, 1677, 1677, 1676, 1676, 1678, 1678, 1672, + 1672, 1688, 1688, 1681, 1681, 1705, 1705, 1705, 1705, + 1711, 1711, 1711, 1711, 1715, 1715, 1715, 1715, 1713, + 1713, 1713, 1713, 1722, 1722, 1723, 1723, 1723, 1723, + 1749, 1620, 1749, 1620, 1729, 1729, 1729, 1729, 1726, + 1726, 1726, 1726, 1746, 1746, 1746, 1620, 1746, 1620, + 1709, 1709, 1709, 1709, 1735, 1735, 1734, 1734, 1736, + 1736, 1735, 1652, 1739, 1739, 1733, 1733, 1737, 1737, + 1744, 1744, 1744, 1744, 1609, 1609, 1610, 1620, 1575, + 1610, 1620, 1575, 1610, 1620, 1749, 1610, 1620, 1749, + 1610, 1620, 1608, 1610, 1620, 1608, 1610, 1620, 1735, + 1610, 1620, 1735, 1610, 1620, 1734, 1610, 1620, 1734, + 1610, 1620, 1736, 1610, 1620, 1736, 1610, 1620, 1744, + 1610, 1620, 1744, 1610, 1620, 1744, 1610, 1620, 1609, + 1610, 1620, 1609, 1610, 1620, 1609, 1740, 1740, 1740, + 1740, 1610, 1620, 1580, 1610, 1620, 1581, 1610, 1620, + 1605, 1610, 1620, 1609, 1610, 1620, 1610, 1576, 1580, + 1576, 1581, 1576, 1582, 1576, 1605, 1576, 1609, 1576, + 1610, 1578, 1580, 1578, 1581, 1578, 1582, 1578, 1605, + 1578, 1609, 1578, 1610, 1579, 1580, 1579, 1605, 1579, + 1609, 1579, 1610, 1580, 1581, 1580, 1605, 1581, 1580, + 1581, 1605, 1582, 1580, 1582, 1581, 1582, 1605, 1587, + 1580, 1587, 1581, 1587, 1582, 1587, 1605, 1589, 1581, + 1589, 1605, 1590, 1580, 1590, 1581, 1590, 1582, 1590, + 1605, 1591, 1581, 1591, 1605, 1592, 1605, 1593, 1580, + 1593, 1605, 1594, 1580, 1594, 1605, 1601, 1580, 1601, + 1581, 1601, 1582, 1601, 1605, 1601, 1609, 1601, 1610, + 1602, 1581, 1602, 1605, 1602, 1609, 1602, 1610, 1603, + 1575, 1603, 1580, 1603, 1581, 1603, 1582, 1603, 1604, + 1603, 1605, 1603, 1609, 1603, 1610, 1604, 1580, 1604, + 1581, 1604, 1582, 1604, 1605, 1604, 1609, 1604, 1610, + 1605, 1580, 1605, 1581, 1605, 1582, 1605, 1605, 1605, + 1609, 1605, 1610, 1606, 1580, 1606, 1581, 1606, 1582, + 1606, 1605, 1606, 1609, 1606, 1610, 1607, 1580, 1607, + 1605, 1607, 1609, 1607, 1610, 1610, 1580, 1610, 1581, + 1610, 1582, 1610, 1605, 1610, 1609, 1610, 1610, 1584, + 1648, 1585, 1648, 1609, 1648, 32, 1612, 1617, 32, + 1613, 1617, 32, 1614, 1617, 32, 1615, 1617, 32, + 1616, 1617, 32, 1617, 1648, 1610, 1620, 1585, 1610, + 1620, 1586, 1610, 1620, 1605, 1610, 1620, 1606, 1610, + 1620, 1609, 1610, 1620, 1610, 1576, 1585, 1576, 1586, + 1576, 1605, 1576, 1606, 1576, 1609, 1576, 1610, 1578, + 1585, 1578, 1586, 1578, 1605, 1578, 1606, 1578, 1609, + 1578, 1610, 1579, 1585, 1579, 1586, 1579, 1605, 1579, + 1606, 1579, 1609, 1579, 1610, 1601, 1609, 1601, 1610, + 1602, 1609, 1602, 1610, 1603, 1575, 1603, 1604, 1603, + 1605, 1603, 1609, 1603, 1610, 1604, 1605, 1604, 1609, + 1604, 1610, 1605, 1575, 1605, 1605, 1606, 1585, 1606, + 1586, 1606, 1605, 1606, 1606, 1606, 1609, 1606, 1610, + 1609, 1648, 1610, 1585, 1610, 1586, 1610, 1605, 1610, + 1606, 1610, 1609, 1610, 1610, 1610, 1620, 1580, 1610, + 1620, 1581, 1610, 1620, 1582, 1610, 1620, 1605, 1610, + 1620, 1607, 1576, 1580, 1576, 1581, 1576, 1582, 1576, + 1605, 1576, 1607, 1578, 1580, 1578, 1581, 1578, 1582, + 1578, 1605, 1578, 1607, 1579, 1605, 1580, 1581, 1580, + 1605, 1581, 1580, 1581, 1605, 1582, 1580, 1582, 1605, + 1587, 1580, 1587, 1581, 1587, 1582, 1587, 1605, 1589, + 1581, 1589, 1582, 1589, 1605, 1590, 1580, 1590, 1581, + 1590, 1582, 1590, 1605, 1591, 1581, 1592, 1605, 1593, + 1580, 1593, 1605, 1594, 1580, 1594, 1605, 1601, 1580, + 1601, 1581, 1601, 1582, 1601, 1605, 1602, 1581, 1602, + 1605, 1603, 1580, 1603, 1581, 1603, 1582, 1603, 1604, + 1603, 1605, 1604, 1580, 1604, 1581, 1604, 1582, 1604, + 1605, 1604, 1607, 1605, 1580, 1605, 1581, 1605, 1582, + 1605, 1605, 1606, 1580, 1606, 1581, 1606, 1582, 1606, + 1605, 1606, 1607, 1607, 1580, 1607, 1605, 1607, 1648, + 1610, 1580, 1610, 1581, 1610, 1582, 1610, 1605, 1610, + 1607, 1610, 1620, 1605, 1610, 1620, 1607, 1576, 1605, + 1576, 1607, 1578, 1605, 1578, 1607, 1579, 1605, 1579, + 1607, 1587, 1605, 1587, 1607, 1588, 1605, 1588, 1607, + 1603, 1604, 1603, 1605, 1604, 1605, 1606, 1605, 1606, + 1607, 1610, 1605, 1610, 1607, 1600, 1614, 1617, 1600, + 1615, 1617, 1600, 1616, 1617, 1591, 1609, 1591, 1610, + 1593, 1609, 1593, 1610, 1594, 1609, 1594, 1610, 1587, + 1609, 1587, 1610, 1588, 1609, 1588, 1610, 1581, 1609, + 1581, 1610, 1580, 1609, 1580, 1610, 1582, 1609, 1582, + 1610, 1589, 1609, 1589, 1610, 1590, 1609, 1590, 1610, + 1588, 1580, 1588, 1581, 1588, 1582, 1588, 1605, 1588, + 1585, 1587, 1585, 1589, 1585, 1590, 1585, 1591, 1609, + 1591, 1610, 1593, 1609, 1593, 1610, 1594, 1609, 1594, + 1610, 1587, 1609, 1587, 1610, 1588, 1609, 1588, 1610, + 1581, 1609, 1581, 1610, 1580, 1609, 1580, 1610, 1582, + 1609, 1582, 1610, 1589, 1609, 1589, 1610, 1590, 1609, + 1590, 1610, 1588, 1580, 1588, 1581, 1588, 1582, 1588, + 1605, 1588, 1585, 1587, 1585, 1589, 1585, 1590, 1585, + 1588, 1580, 1588, 1581, 1588, 1582, 1588, 1605, 1587, + 1607, 1588, 1607, 1591, 1605, 1587, 1580, 1587, 1581, + 1587, 1582, 1588, 1580, 1588, 1581, 1588, 1582, 1591, + 1605, 1592, 1605, 1575, 1611, 1575, 1611, 1578, 1580, + 1605, 1578, 1581, 1580, 1578, 1581, 1580, 1578, 1581, + 1605, 1578, 1582, 1605, 1578, 1605, 1580, 1578, 1605, + 1581, 1578, 1605, 1582, 1580, 1605, 1581, 1580, 1605, + 1581, 1581, 1605, 1610, 1581, 1605, 1609, 1587, 1581, + 1580, 1587, 1580, 1581, 1587, 1580, 1609, 1587, 1605, + 1581, 1587, 1605, 1581, 1587, 1605, 1580, 1587, 1605, + 1605, 1587, 1605, 1605, 1589, 1581, 1581, 1589, 1581, + 1581, 1589, 1605, 1605, 1588, 1581, 1605, 1588, 1581, + 1605, 1588, 1580, 1610, 1588, 1605, 1582, 1588, 1605, + 1582, 1588, 1605, 1605, 1588, 1605, 1605, 1590, 1581, + 1609, 1590, 1582, 1605, 1590, 1582, 1605, 1591, 1605, + 1581, 1591, 1605, 1581, 1591, 1605, 1605, 1591, 1605, + 1610, 1593, 1580, 1605, 1593, 1605, 1605, 1593, 1605, + 1605, 1593, 1605, 1609, 1594, 1605, 1605, 1594, 1605, + 1610, 1594, 1605, 1609, 1601, 1582, 1605, 1601, 1582, + 1605, 1602, 1605, 1581, 1602, 1605, 1605, 1604, 1581, + 1605, 1604, 1581, 1610, 1604, 1581, 1609, 1604, 1580, + 1580, 1604, 1580, 1580, 1604, 1582, 1605, 1604, 1582, + 1605, 1604, 1605, 1581, 1604, 1605, 1581, 1605, 1581, + 1580, 1605, 1581, 1605, 1605, 1581, 1610, 1605, 1580, + 1581, 1605, 1580, 1605, 1605, 1582, 1580, 1605, 1582, + 1605, 1605, 1580, 1582, 1607, 1605, 1580, 1607, 1605, + 1605, 1606, 1581, 1605, 1606, 1581, 1609, 1606, 1580, + 1605, 1606, 1580, 1605, 1606, 1580, 1609, 1606, 1605, + 1610, 1606, 1605, 1609, 1610, 1605, 1605, 1610, 1605, + 1605, 1576, 1582, 1610, 1578, 1580, 1610, 1578, 1580, + 1609, 1578, 1582, 1610, 1578, 1582, 1609, 1578, 1605, + 1610, 1578, 1605, 1609, 1580, 1605, 1610, 1580, 1581, + 1609, 1580, 1605, 1609, 1587, 1582, 1609, 1589, 1581, + 1610, 1588, 1581, 1610, 1590, 1581, 1610, 1604, 1580, + 1610, 1604, 1605, 1610, 1610, 1581, 1610, 1610, 1580, + 1610, 1610, 1605, 1610, 1605, 1605, 1610, 1602, 1605, + 1610, 1606, 1581, 1610, 1602, 1605, 1581, 1604, 1581, + 1605, 1593, 1605, 1610, 1603, 1605, 1610, 1606, 1580, + 1581, 1605, 1582, 1610, 1604, 1580, 1605, 1603, 1605, + 1605, 1604, 1580, 1605, 1606, 1580, 1581, 1580, 1581, + 1610, 1581, 1580, 1610, 1605, 1580, 1610, 1601, 1605, + 1610, 1576, 1581, 1610, 1603, 1605, 1605, 1593, 1580, + 1605, 1589, 1605, 1605, 1587, 1582, 1610, 1606, 1580, + 1610, 1589, 1604, 1746, 1602, 1604, 1746, 1575, 1604, + 1604, 1607, 1575, 1603, 1576, 1585, 1605, 1581, 1605, + 1583, 1589, 1604, 1593, 1605, 1585, 1587, 1608, 1604, + 1593, 1604, 1610, 1607, 1608, 1587, 1604, 1605, 1589, + 1604, 1609, 1589, 1604, 1609, 32, 1575, 1604, 1604, + 1607, 32, 1593, 1604, 1610, 1607, 32, 1608, 1587, + 1604, 1605, 1580, 1604, 32, 1580, 1604, 1575, 1604, + 1607, 1585, 1740, 1575, 1604, 44, 12289, 12290, 58, + 59, 33, 63, 12310, 12311, 46, 46, 46, 46, + 46, 8212, 8211, 95, 95, 40, 41, 123, 125, + 12308, 12309, 12304, 12305, 12298, 12299, 12296, 12297, 12300, + 12301, 12302, 12303, 91, 93, 32, 773, 32, 773, + 32, 773, 32, 773, 95, 95, 95, 44, 12289, + 46, 59, 58, 63, 33, 8212, 40, 41, 123, + 125, 12308, 12309, 35, 38, 42, 43, 45, 60, + 62, 61, 92, 36, 37, 64, 32, 1611, 1600, + 1611, 32, 1612, 32, 1613, 32, 1614, 1600, 1614, + 32, 1615, 1600, 1615, 32, 1616, 1600, 1616, 32, + 1617, 1600, 1617, 32, 1618, 1600, 1618, 1569, 1575, + 1619, 1575, 1619, 1575, 1620, 1575, 1620, 1608, 1620, + 1608, 1620, 1575, 1621, 1575, 1621, 1610, 1620, 1610, + 1620, 1610, 1620, 1610, 1620, 1575, 1575, 1576, 1576, + 1576, 1576, 1577, 1577, 1578, 1578, 1578, 1578, 1579, + 1579, 1579, 1579, 1580, 1580, 1580, 1580, 1581, 1581, + 1581, 1581, 1582, 1582, 1582, 1582, 1583, 1583, 1584, + 1584, 1585, 1585, 1586, 1586, 1587, 1587, 1587, 1587, + 1588, 1588, 1588, 1588, 1589, 1589, 1589, 1589, 1590, + 1590, 1590, 1590, 1591, 1591, 1591, 1591, 1592, 1592, + 1592, 1592, 1593, 1593, 1593, 1593, 1594, 1594, 1594, + 1594, 1601, 1601, 1601, 1601, 1602, 1602, 1602, 1602, + 1603, 1603, 1603, 1603, 1604, 1604, 1604, 1604, 1605, + 1605, 1605, 1605, 1606, 1606, 1606, 1606, 1607, 1607, + 1607, 1607, 1608, 1608, 1609, 1609, 1610, 1610, 1610, + 1610, 1604, 1575, 1619, 1604, 1575, 1619, 1604, 1575, + 1620, 1604, 1575, 1620, 1604, 1575, 1621, 1604, 1575, + 1621, 1604, 1575, 1604, 1575, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, + 10629, 10630, 12290, 12300, 12301, 12289, 12539, 12530, 12449, + 12451, 12453, 12455, 12457, 12515, 12517, 12519, 12483, 12540, + 12450, 12452, 12454, 12456, 12458, 12459, 12461, 12463, 12465, + 12467, 12469, 12471, 12473, 12475, 12477, 12479, 12481, 12484, + 12486, 12488, 12490, 12491, 12492, 12493, 12494, 12495, 12498, + 12501, 12504, 12507, 12510, 12511, 12512, 12513, 12514, 12516, + 12518, 12520, 12521, 12522, 12523, 12524, 12525, 12527, 12531, + 12441, 12442, 4448, 4352, 4353, 4522, 4354, 4524, 4525, + 4355, 4356, 4357, 4528, 4529, 4530, 4531, 4532, 4533, + 4378, 4358, 4359, 4360, 4385, 4361, 4362, 4363, 4364, + 4365, 4366, 4367, 4368, 4369, 4370, 4449, 4450, 4451, + 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, + 4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469, + 162, 163, 172, 32, 772, 166, 165, 8361, 9474, + 8592, 8593, 8594, 8595, 9632, 9675, 720, 721, 230, + 665, 595, 675, 43878, 677, 676, 598, 599, 7569, + 600, 606, 681, 612, 610, 608, 667, 295, 668, + 615, 644, 682, 683, 620, 122628, 42894, 622, 122629, + 654, 122630, 248, 630, 631, 113, 634, 122632, 637, + 638, 640, 680, 678, 43879, 679, 648, 11377, 655, + 673, 674, 664, 448, 449, 450, 122634, 122654, 69785, + 69818, 69787, 69818, 69797, 69818, 69937, 69927, 69938, 69927, + 70471, 70462, 70471, 70487, 70841, 70842, 70841, 70832, 70841, + 70845, 71096, 71087, 71097, 71087, 71989, 71984, 119127, 119141, + 119128, 119141, 119128, 119141, 119150, 119128, 119141, 119151, 119128, + 119141, 119152, 119128, 119141, 119153, 119128, 119141, 119154, 119225, + 119141, 119226, 119141, 119225, 119141, 119150, 119226, 119141, 119150, + 119225, 119141, 119151, 119226, 119141, 119151, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 97, 98, 99, 100, 101, 102, + 103, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, + 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 65, + 67, 68, 71, 74, 75, 78, 79, 80, 81, + 83, 84, 85, 86, 87, 88, 89, 90, 97, + 98, 99, 100, 102, 104, 105, 106, 107, 108, + 109, 110, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 65, 66, 68, 69, 70, 71, 74, + 75, 76, 77, 78, 79, 80, 81, 83, 84, + 85, 86, 87, 88, 89, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 65, 66, 68, 69, 70, + 71, 73, 74, 75, 76, 77, 79, 83, 84, + 85, 86, 87, 88, 89, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, + 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 305, 567, 913, 914, 915, 916, 917, 918, + 919, 920, 921, 922, 923, 924, 925, 926, 927, + 928, 929, 920, 931, 932, 933, 934, 935, 936, + 937, 8711, 945, 946, 947, 948, 949, 950, 951, + 952, 953, 954, 955, 956, 957, 958, 959, 960, + 961, 962, 963, 964, 965, 966, 967, 968, 969, + 8706, 949, 952, 954, 966, 961, 960, 913, 914, + 915, 916, 917, 918, 919, 920, 921, 922, 923, + 924, 925, 926, 927, 928, 929, 920, 931, 932, + 933, 934, 935, 936, 937, 8711, 945, 946, 947, + 948, 949, 950, 951, 952, 953, 954, 955, 956, + 957, 958, 959, 960, 961, 962, 963, 964, 965, + 966, 967, 968, 969, 8706, 949, 952, 954, 966, + 961, 960, 913, 914, 915, 916, 917, 918, 919, + 920, 921, 922, 923, 924, 925, 926, 927, 928, + 929, 920, 931, 932, 933, 934, 935, 936, 937, + 8711, 945, 946, 947, 948, 949, 950, 951, 952, + 953, 954, 955, 956, 957, 958, 959, 960, 961, + 962, 963, 964, 965, 966, 967, 968, 969, 8706, + 949, 952, 954, 966, 961, 960, 913, 914, 915, + 916, 917, 918, 919, 920, 921, 922, 923, 924, + 925, 926, 927, 928, 929, 920, 931, 932, 933, + 934, 935, 936, 937, 8711, 945, 946, 947, 948, + 949, 950, 951, 952, 953, 954, 955, 956, 957, + 958, 959, 960, 961, 962, 963, 964, 965, 966, + 967, 968, 969, 8706, 949, 952, 954, 966, 961, + 960, 913, 914, 915, 916, 917, 918, 919, 920, + 921, 922, 923, 924, 925, 926, 927, 928, 929, + 920, 931, 932, 933, 934, 935, 936, 937, 8711, + 945, 946, 947, 948, 949, 950, 951, 952, 953, + 954, 955, 956, 957, 958, 959, 960, 961, 962, + 963, 964, 965, 966, 967, 968, 969, 8706, 949, + 952, 954, 966, 961, 960, 988, 989, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, + 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 1072, 1073, 1074, 1075, 1076, 1077, + 1078, 1079, 1080, 1082, 1083, 1084, 1086, 1087, 1088, + 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1099, + 1101, 1102, 42633, 1241, 1110, 1112, 1257, 1199, 1231, + 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, + 1082, 1083, 1086, 1087, 1089, 1091, 1092, 1093, 1094, + 1095, 1096, 1098, 1099, 1169, 1110, 1109, 1119, 1195, + 42577, 1201, 1575, 1576, 1580, 1583, 1608, 1586, 1581, + 1591, 1610, 1603, 1604, 1605, 1606, 1587, 1593, 1601, + 1589, 1602, 1585, 1588, 1578, 1579, 1582, 1584, 1590, + 1592, 1594, 1646, 1722, 1697, 1647, 1576, 1580, 1607, + 1581, 1610, 1603, 1604, 1605, 1606, 1587, 1593, 1601, + 1589, 1602, 1588, 1578, 1579, 1582, 1590, 1594, 1580, + 1581, 1610, 1604, 1606, 1587, 1593, 1589, 1602, 1588, + 1582, 1590, 1594, 1722, 1647, 1576, 1580, 1607, 1581, + 1591, 1610, 1603, 1605, 1606, 1587, 1593, 1601, 1589, + 1602, 1588, 1578, 1579, 1582, 1590, 1592, 1594, 1646, + 1697, 1575, 1576, 1580, 1583, 1607, 1608, 1586, 1581, + 1591, 1610, 1604, 1605, 1606, 1587, 1593, 1601, 1589, + 1602, 1585, 1588, 1578, 1579, 1582, 1584, 1590, 1592, + 1594, 1576, 1580, 1583, 1608, 1586, 1581, 1591, 1610, + 1604, 1605, 1606, 1587, 1593, 1601, 1589, 1602, 1585, + 1588, 1578, 1579, 1582, 1584, 1590, 1592, 1594, 48, + 46, 48, 44, 49, 44, 50, 44, 51, 44, + 52, 44, 53, 44, 54, 44, 55, 44, 56, + 44, 57, 44, 40, 65, 41, 40, 66, 41, + 40, 67, 41, 40, 68, 41, 40, 69, 41, + 40, 70, 41, 40, 71, 41, 40, 72, 41, + 40, 73, 41, 40, 74, 41, 40, 75, 41, + 40, 76, 41, 40, 77, 41, 40, 78, 41, + 40, 79, 41, 40, 80, 41, 40, 81, 41, + 40, 82, 41, 40, 83, 41, 40, 84, 41, + 40, 85, 41, 40, 86, 41, 40, 87, 41, + 40, 88, 41, 40, 89, 41, 40, 90, 41, + 12308, 83, 12309, 67, 82, 67, 68, 87, 90, + 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 72, + 86, 77, 86, 83, 68, 83, 83, 80, 80, + 86, 87, 67, 77, 67, 77, 68, 77, 82, + 68, 74, 12411, 12363, 12467, 12467, 12469, 25163, 23383, + 21452, 12486, 12441, 20108, 22810, 35299, 22825, 20132, 26144, + 28961, 26009, 21069, 24460, 20877, 26032, 21021, 32066, 29983, + 36009, 22768, 21561, 28436, 25237, 25429, 19968, 19977, 36938, + 24038, 20013, 21491, 25351, 36208, 25171, 31105, 31354, 21512, + 28288, 26377, 26376, 30003, 21106, 21942, 37197, 12308, 26412, + 12309, 12308, 19977, 12309, 12308, 20108, 12309, 12308, 23433, + 12309, 12308, 28857, 12309, 12308, 25171, 12309, 12308, 30423, + 12309, 12308, 21213, 12309, 12308, 25943, 12309, 24471, 21487, + 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 20029, 20024, 20033, 131362, 20320, 20398, 20411, 20482, + 20602, 20633, 20711, 20687, 13470, 132666, 20813, 20820, 20836, + 20855, 132380, 13497, 20839, 20877, 132427, 20887, 20900, 20172, + 20908, 20917, 168415, 20981, 20995, 13535, 21051, 21062, 21106, + 21111, 13589, 21191, 21193, 21220, 21242, 21253, 21254, 21271, + 21321, 21329, 21338, 21363, 21373, 21375, 21375, 21375, 133676, + 28784, 21450, 21471, 133987, 21483, 21489, 21510, 21662, 21560, + 21576, 21608, 21666, 21750, 21776, 21843, 21859, 21892, 21892, + 21913, 21931, 21939, 21954, 22294, 22022, 22295, 22097, 22132, + 20999, 22766, 22478, 22516, 22541, 22411, 22578, 22577, 22700, + 136420, 22770, 22775, 22790, 22810, 22818, 22882, 136872, 136938, + 23020, 23067, 23079, 23000, 23142, 14062, 14076, 23304, 23358, + 23358, 137672, 23491, 23512, 23527, 23539, 138008, 23551, 23558, + 24403, 23586, 14209, 23648, 23662, 23744, 23693, 138724, 23875, + 138726, 23918, 23915, 23932, 24033, 24034, 14383, 24061, 24104, + 24125, 24169, 14434, 139651, 14460, 24240, 24243, 24246, 24266, + 172946, 24318, 140081, 140081, 33281, 24354, 24354, 14535, 144056, + 156122, 24418, 24427, 14563, 24474, 24525, 24535, 24569, 24705, + 14650, 14620, 24724, 141012, 24775, 24904, 24908, 24910, 24908, + 24954, 24974, 25010, 24996, 25007, 25054, 25074, 25078, 25104, + 25115, 25181, 25265, 25300, 25424, 142092, 25405, 25340, 25448, + 25475, 25572, 142321, 25634, 25541, 25513, 14894, 25705, 25726, + 25757, 25719, 14956, 25935, 25964, 143370, 26083, 26360, 26185, + 15129, 26257, 15112, 15076, 20882, 20885, 26368, 26268, 32941, + 17369, 26391, 26395, 26401, 26462, 26451, 144323, 15177, 26618, + 26501, 26706, 26757, 144493, 26766, 26655, 26900, 15261, 26946, + 27043, 27114, 27304, 145059, 27355, 15384, 27425, 145575, 27476, + 15438, 27506, 27551, 27578, 27579, 146061, 138507, 146170, 27726, + 146620, 27839, 27853, 27751, 27926, 27966, 28023, 27969, 28009, + 28024, 28037, 146718, 27956, 28207, 28270, 15667, 28363, 28359, + 147153, 28153, 28526, 147294, 147342, 28614, 28729, 28702, 28699, + 15766, 28746, 28797, 28791, 28845, 132389, 28997, 148067, 29084, + 148395, 29224, 29237, 29264, 149000, 29312, 29333, 149301, 149524, + 29562, 29579, 16044, 29605, 16056, 16056, 29767, 29788, 29809, + 29829, 29898, 16155, 29988, 150582, 30014, 150674, 30064, 139679, + 30224, 151457, 151480, 151620, 16380, 16392, 30452, 151795, 151794, + 151833, 151859, 30494, 30495, 30495, 30538, 16441, 30603, 16454, + 16534, 152605, 30798, 30860, 30924, 16611, 153126, 31062, 153242, + 153285, 31119, 31211, 16687, 31296, 31306, 31311, 153980, 154279, + 154279, 31470, 16898, 154539, 31686, 31689, 16935, 154752, 31954, + 17056, 31976, 31971, 32000, 155526, 32099, 17153, 32199, 32258, + 32325, 17204, 156200, 156231, 17241, 156377, 32634, 156478, 32661, + 32762, 32773, 156890, 156963, 32864, 157096, 32880, 144223, 17365, + 32946, 33027, 17419, 33086, 23221, 157607, 157621, 144275, 144284, + 33281, 33284, 36766, 17515, 33425, 33419, 33437, 21171, 33457, + 33459, 33469, 33510, 158524, 33509, 33565, 33635, 33709, 33571, + 33725, 33767, 33879, 33619, 33738, 33740, 33756, 158774, 159083, + 158933, 17707, 34033, 34035, 34070, 160714, 34148, 159532, 17757, + 17761, 159665, 159954, 17771, 34384, 34396, 34407, 34409, 34473, + 34440, 34574, 34530, 34681, 34600, 34667, 34694, 17879, 34785, + 34817, 17913, 34912, 34915, 161383, 35031, 35038, 17973, 35066, + 13499, 161966, 162150, 18110, 18119, 35488, 35565, 35722, 35925, + 162984, 36011, 36033, 36123, 36215, 163631, 133124, 36299, 36284, + 36336, 133342, 36564, 36664, 165330, 165357, 37012, 37105, 37137, + 165678, 37147, 37432, 37591, 37592, 37500, 37881, 37909, 166906, + 38283, 18837, 38327, 167287, 18918, 38595, 23986, 38691, 168261, + 168474, 19054, 19062, 38880, 168970, 19122, 169110, 38923, 38923, + 38953, 169398, 39138, 19251, 39209, 39335, 39362, 39422, 19406, + 170800, 39698, 40000, 40189, 19662, 19693, 40295, 172238, 19704, + 172293, 172558, 172689, 40635, 19798, 40697, 40702, 40709, 40719, + 40726, 40763, 173568}; + +const uint8_t canonical_combining_class_index[4352] = { + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 0, + 15, 0, 0, 0, 16, 17, 18, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 24, 25, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 28, 29, 30, + 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 0, 0, 33, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 52, + 53, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 55, 56, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 61, 56, 62, 0, 63, 0, 0, 0, 64, 65, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}; +const uint8_t canonical_combining_class_block[67][256] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216, 220, 220, + 220, 220, 220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220, + 220, 230, 230, 230, 230, 230, 230, 230, 230, 240, 230, 220, 220, 220, 230, + 230, 230, 220, 220, 0, 230, 230, 230, 220, 220, 220, 220, 230, 232, 220, + 220, 230, 233, 234, 234, 233, 234, 234, 233, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, + 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 230, 230, 230, 230, + 220, 230, 230, 230, 222, 220, 230, 230, 230, 230, 230, 230, 220, 220, 220, + 220, 220, 220, 230, 230, 220, 230, 230, 222, 228, 230, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, + 0, 230, 220, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 230, 230, 230, 230, 230, 230, 230, 230, 30, 31, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 27, 28, 29, 30, 31, 32, 33, 34, 230, 230, 220, 220, 230, 230, 230, + 230, 230, 220, 230, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230, 230, + 230, 230, 220, 230, 0, 0, 230, 230, 0, 220, 230, 230, 220, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220, + 220, 230, 220, 230, 230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, + 230, 230, 220, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 0, 230, 230, 230, 0, 230, 230, 230, 230, + 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, + 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 230, 220, 220, 220, 230, 230, 230, 230, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 220, 220, 220, + 220, 220, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230, 0, 220, 230, 230, 220, 230, 230, 220, 230, 230, 230, 220, 220, 220, + 27, 28, 29, 230, 230, 230, 220, 230, 230, 220, 220, 230, 230, 230, 230, + 230}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 230, 220, 230, 230, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 103, 103, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 107, 107, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 118, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 122, 122, 122, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 129, 130, 0, 132, 0, 0, 0, + 0, 0, 130, 130, 130, 130, 0, 0, 130, 0, 230, 230, 9, 0, 230, + 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 230, 220, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, + 230, 230, 230, 230, 230, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, + 230, 220, 220, 220, 220, 220, 220, 230, 230, 220, 0, 220, 220, 230, 230, + 220, 220, 230, 230, 230, 230, 230, 220, 230, 230, 230, 230, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 230, 230, 230, 230, 230, + 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, + 230, 0, 1, 220, 220, 220, 220, 220, 230, 230, 220, 220, 220, 220, 230, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 220, 0, 0, + 0, 0, 0, 0, 230, 0, 0, 0, 230, 230, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 220, + 230, 230, 230, 230, 230, 230, 230, 220, 230, 230, 234, 214, 220, 202, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 232, 228, 228, 220, 218, 230, 233, 220, 230, + 220}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 230, 230, 1, 1, 230, 230, 230, 230, 1, 1, 1, 230, 230, 0, 0, 0, + 0, 230, 0, 0, 0, 1, 1, 230, 220, 230, 1, 1, 220, 220, 220, 220, + 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 218, 228, 232, 222, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, + 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, + 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 230, 0, 230, 230, 220, 0, 0, 230, 230, 0, 0, 0, 0, 0, + 230, 230, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 230, 230, 230, 230, 230, 230, 230, 220, 220, 220, 220, 220, 220, + 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 230, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 1, 220, 0, + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, + 230, 230, 230, 220, 230, 220, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 230, 220, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, + 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 216, 216, 1, 1, 1, 0, 0, 0, 226, 216, 216, + 216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220, + 220, 220, 220, 0, 0, 230, 230, 230, 230, 230, 220, 220, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {230, 230, 230, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230, 230, 230, + 230, 230, 230, 230, 0, 230, 230, 0, 230, 230, 230, 230, 230, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 232, 220, 230, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220, 220, 220, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + +const uint8_t composition_index[4352] = { + 0, 1, 2, 3, 4, 5, 6, 5, 5, 7, 5, 8, 9, 10, 5, 5, 11, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 12, 5, 5, 13, 14, 5, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 18, 19, 5, 20, 21, 22, 5, 5, 5, 23, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; +const uint16_t composition_block[67][257] = { + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 5, 7, 7, 7, 39, 45, 55, 67, 101, 103, 117, 131, 161, + 163, 173, 185, 191, 209, 241, 245, 245, 261, 275, 289, 327, 331, 343, 347, + 365, 377, 377, 377, 377, 377, 377, 377, 409, 415, 425, 437, 471, 473, 487, + 503, 531, 535, 545, 557, 563, 581, 613, 617, 617, 633, 647, 663, 701, 705, + 719, 723, 743, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, + 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, + 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, + 755, 755, 755, 755, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, + 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, + 769, 769, 771, 773, 777, 779, 779, 779, 787, 787, 787, 787, 787, 789, 789, + 789, 789, 789, 797, 803, 805, 805, 807, 807, 807, 807, 815, 815, 815, 815, + 815, 815, 823, 823, 825, 827, 831, 833, 833, 833, 841, 841, 841, 841, 841, + 843, 843, 843, 843, 843, 851, 857, 859, 859, 861, 861, 861, 861, 869, 869, + 869, 869}, + {869, 869, 869, 877, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, + 885, 885, 885, 885, 889, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, + 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, + 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, + 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, + 893, 893, 897, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, + 901, 903, 905, 905, 905, 905, 905, 907, 909, 909, 909, 909, 909, 909, 909, + 911, 913, 915, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, + 917, 917, 917, 917, 917, 917, 917, 917, 919, 919, 919, 919, 919, 919, 919, + 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, + 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 929, 939, 939, 939, + 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 949, 959, 959, 959, + 959, 959, 959, 959, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, + 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, + 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, + 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 963, 965, 965, 965, 965, + 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, + 965, 965}, + {965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, + 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, + 965, 965, 965, 965, 965, 965, 965, 965, 965, 967, 969, 971, 973, 973, 973, + 973, 973, 975, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, + 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, + 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, + 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, + 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, + 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, + 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979}, + {979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, + 979, 979, 993, 993, 993, 993, 1001, 1001, 1011, 1011, 1025, 1025, + 1025, 1025, 1025, 1025, 1033, 1033, 1035, 1035, 1035, 1035, 1047, 1047, + 1047, 1047, 1057, 1057, 1057, 1059, 1059, 1061, 1061, 1061, 1077, 1077, + 1077, 1077, 1085, 1085, 1097, 1097, 1113, 1113, 1113, 1113, 1113, 1113, + 1121, 1121, 1125, 1125, 1125, 1125, 1141, 1141, 1141, 1141, 1153, 1159, + 1165, 1165, 1165, 1167, 1167, 1167, 1167, 1171, 1171, 1171, 1171, 1171, + 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, + 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, + 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, + 1171, 1171, 1171, 1171, 1171}, + {1171, 1171, 1171, 1171, 1171, 1171, 1171, 1173, 1173, 1173, 1173, 1173, + 1173, 1173, 1173, 1173, 1173, 1177, 1177, 1177, 1179, 1179, 1185, 1189, + 1191, 1199, 1199, 1201, 1201, 1201, 1201, 1203, 1203, 1203, 1203, 1203, + 1211, 1211, 1211, 1211, 1213, 1213, 1213, 1213, 1215, 1215, 1217, 1217, + 1217, 1221, 1221, 1221, 1223, 1223, 1229, 1233, 1235, 1243, 1243, 1245, + 1245, 1245, 1245, 1247, 1247, 1247, 1247, 1247, 1255, 1255, 1255, 1255, + 1257, 1257, 1257, 1257, 1259, 1259, 1261, 1261, 1261, 1261, 1261, 1261, + 1261, 1261, 1261, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, + 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, + 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1265, 1267, 1267, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1267, 1269, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, + 1271, 1271, 1271, 1271, 1271, 1273, 1275, 1275, 1275, 1275, 1275, 1275, + 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, + 1275, 1275, 1275, 1275, 1275}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, + 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, + 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, + 1275, 1275, 1275, 1275, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + 1281, 1283, 1283, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, + 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1289, 1289, 1289, 1291, 1291, + 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, + 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, + 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, + 1291, 1291, 1291, 1291, 1291}, + {1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, + 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, + 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, + 1291, 1291, 1291, 1291, 1291, 1293, 1293, 1293, 1293, 1293, 1293, 1293, + 1293, 1295, 1295, 1295, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, + 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301}, + {1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, + 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, + 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, + 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, + 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, + 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, + 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, + 1307, 1307, 1307, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1313, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315}, + {1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, + 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1325, 1325, 1325, 1325, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327}, + {1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1331, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1339, 1339, 1339, 1341, 1341, 1341, 1341, 1341, 1341, 1341, + 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, + 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, + 1341, 1341, 1341, 1341, 1341}, + {1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, + 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, + 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, + 1341, 1341, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, + 1343, 1343, 1343, 1343, 1343}, + {1343, 1343, 1343, 1343, 1343, 1343, 1345, 1345, 1347, 1347, 1349, 1349, + 1351, 1351, 1353, 1353, 1353, 1353, 1355, 1355, 1355, 1355, 1355, 1355, + 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, + 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, + 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1357, + 1357, 1359, 1359, 1361, 1363, 1363, 1363, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365}, + {1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1367, 1369, 1369, 1369, 1369, + 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, + 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, + 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1371, 1373, 1373, 1373, 1373, + 1373, 1373, 1373, 1375, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, + 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, + 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, + 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, + 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, + 1377, 1377, 1377, 1377, 1377, 1381, 1385, 1385, 1385, 1385, 1385, 1385, + 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, + 1385, 1385, 1385, 1385, 1385, 1387, 1389, 1389, 1389, 1389, 1389, 1389, + 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, + 1389, 1391, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, + 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, + 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, + 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, + 1393, 1393, 1393, 1393, 1393}, + {1393, 1401, 1409, 1411, 1413, 1415, 1417, 1419, 1421, 1429, 1437, 1439, + 1441, 1443, 1445, 1447, 1449, 1453, 1457, 1457, 1457, 1457, 1457, 1457, + 1457, 1461, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1473, 1481, 1483, + 1485, 1487, 1489, 1491, 1493, 1501, 1509, 1511, 1513, 1515, 1517, 1519, + 1521, 1527, 1533, 1533, 1533, 1533, 1533, 1533, 1533, 1539, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1549, 1553, 1553, 1553, 1553, 1553, 1553, + 1553, 1557, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1567, 1573, 1573, + 1573, 1573, 1573, 1573, 1573, 1573, 1579, 1579, 1579, 1579, 1579, 1579, + 1579, 1587, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1615, 1623, 1625, + 1627, 1629, 1631, 1633, 1635, 1637, 1637, 1637, 1637, 1639, 1639, 1639, + 1639, 1639, 1639, 1639, 1639, 1641, 1641, 1641, 1641, 1641, 1641, 1641, + 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, + 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, + 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, + 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, + 1641, 1641, 1641, 1643, 1643, 1643, 1643, 1643, 1643, 1643, 1643, 1643, + 1649, 1649, 1649, 1649, 1649, 1649, 1649, 1651, 1651, 1651, 1651, 1651, + 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, + 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, + 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, + 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1653, 1653, 1653, 1653, 1653, + 1653, 1653, 1653, 1659, 1659}, + {1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1661, 1661, 1663, 1663, 1665, 1665, 1665, 1665, 1665, 1665, 1665, + 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, + 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, + 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, + 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665, + 1665, 1665, 1665, 1665, 1665, 1667, 1667, 1669, 1669, 1671, 1671, 1671, + 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, + 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, + 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, 1671, + 1671, 1671, 1671, 1671, 1671}, + {1671, 1671, 1671, 1671, 1673, 1673, 1673, 1673, 1673, 1675, 1675, 1675, + 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, + 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, + 1679, 1679, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, + 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, + 1681, 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1685, 1685, 1687, 1687, + 1687, 1689, 1689, 1689, 1689, 1689, 1691, 1691, 1691, 1691, 1691, 1691, + 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1691, + 1691, 1691, 1693, 1693, 1693, 1695, 1697, 1697, 1697, 1697, 1697, 1697, + 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1699, 1701, 1701, 1701, 1703, + 1705, 1705, 1705, 1707, 1709, 1711, 1713, 1713, 1713, 1713, 1713, 1715, + 1717, 1717, 1717, 1719, 1721, 1721, 1721, 1721, 1721, 1721, 1721, 1721, + 1721, 1721, 1723, 1725, 1725, 1725, 1725, 1725, 1725, 1725, 1725, 1725, + 1725, 1725, 1725, 1725, 1725, 1725, 1725, 1727, 1727, 1727, 1727, 1727, + 1727, 1729, 1731, 1731, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1735, + 1737, 1739, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741}, + {1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1741, 1743, + 1743, 1743, 1743, 1743, 1745, 1745, 1747, 1747, 1749, 1749, 1751, 1751, + 1753, 1753, 1755, 1755, 1757, 1757, 1759, 1759, 1761, 1761, 1763, 1763, + 1765, 1765, 1767, 1767, 1767, 1769, 1769, 1771, 1771, 1773, 1773, 1773, + 1773, 1773, 1773, 1773, 1777, 1777, 1777, 1781, 1781, 1781, 1785, 1785, + 1785, 1789, 1789, 1789, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, + 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, + 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, 1793, + 1793, 1793, 1795, 1795, 1795, 1795, 1795, 1795, 1795, 1795, 1795, 1797, + 1797, 1797, 1797, 1797, 1799, 1799, 1801, 1801, 1803, 1803, 1805, 1805, + 1807, 1807, 1809, 1809, 1811, 1811, 1813, 1813, 1815, 1815, 1817, 1817, + 1819, 1819, 1821, 1821, 1821, 1823, 1823, 1825, 1825, 1827, 1827, 1827, + 1827, 1827, 1827, 1827, 1831, 1831, 1831, 1835, 1835, 1835, 1839, 1839, + 1839, 1843, 1843, 1843, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, + 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, 1847, + 1849, 1851, 1853, 1855, 1855, 1855, 1855, 1855, 1855, 1855, 1855, 1855, + 1855, 1855, 1857, 1857, 1857}, + {1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, + 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1857, 1859, 1859, + 1861, 1861, 1861, 1861, 1861, 1861, 1861, 1861, 1861, 1861, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863}, + {1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, 1863, + 1863, 1863, 1865, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867}, + {1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, 1867, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871}, + {1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, 1871, + 1871, 1871, 1871, 1871, 1871, 1871, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877}, + {1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + 1877, 1877, 1877, 1877, 1877, 1879, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881}, + {1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881, + 1881, 1881, 1881, 1881, 1881, 1881, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883, + 1883, 1883, 1883, 1883, 1883}}; +const char32_t composition_data[1883] = { + 0, 824, 8814, 824, 8800, 824, 8815, 768, 192, 769, 193, + 770, 194, 771, 195, 772, 256, 774, 258, 775, 550, 776, + 196, 777, 7842, 778, 197, 780, 461, 783, 512, 785, 514, + 803, 7840, 805, 7680, 808, 260, 775, 7682, 803, 7684, 817, + 7686, 769, 262, 770, 264, 775, 266, 780, 268, 807, 199, + 775, 7690, 780, 270, 803, 7692, 807, 7696, 813, 7698, 817, + 7694, 768, 200, 769, 201, 770, 202, 771, 7868, 772, 274, + 774, 276, 775, 278, 776, 203, 777, 7866, 780, 282, 783, + 516, 785, 518, 803, 7864, 807, 552, 808, 280, 813, 7704, + 816, 7706, 775, 7710, 769, 500, 770, 284, 772, 7712, 774, + 286, 775, 288, 780, 486, 807, 290, 770, 292, 775, 7714, + 776, 7718, 780, 542, 803, 7716, 807, 7720, 814, 7722, 768, + 204, 769, 205, 770, 206, 771, 296, 772, 298, 774, 300, + 775, 304, 776, 207, 777, 7880, 780, 463, 783, 520, 785, + 522, 803, 7882, 808, 302, 816, 7724, 770, 308, 769, 7728, + 780, 488, 803, 7730, 807, 310, 817, 7732, 769, 313, 780, + 317, 803, 7734, 807, 315, 813, 7740, 817, 7738, 769, 7742, + 775, 7744, 803, 7746, 768, 504, 769, 323, 771, 209, 775, + 7748, 780, 327, 803, 7750, 807, 325, 813, 7754, 817, 7752, + 768, 210, 769, 211, 770, 212, 771, 213, 772, 332, 774, + 334, 775, 558, 776, 214, 777, 7886, 779, 336, 780, 465, + 783, 524, 785, 526, 795, 416, 803, 7884, 808, 490, 769, + 7764, 775, 7766, 769, 340, 775, 7768, 780, 344, 783, 528, + 785, 530, 803, 7770, 807, 342, 817, 7774, 769, 346, 770, + 348, 775, 7776, 780, 352, 803, 7778, 806, 536, 807, 350, + 775, 7786, 780, 356, 803, 7788, 806, 538, 807, 354, 813, + 7792, 817, 7790, 768, 217, 769, 218, 770, 219, 771, 360, + 772, 362, 774, 364, 776, 220, 777, 7910, 778, 366, 779, + 368, 780, 467, 783, 532, 785, 534, 795, 431, 803, 7908, + 804, 7794, 808, 370, 813, 7798, 816, 7796, 771, 7804, 803, + 7806, 768, 7808, 769, 7810, 770, 372, 775, 7814, 776, 7812, + 803, 7816, 775, 7818, 776, 7820, 768, 7922, 769, 221, 770, + 374, 771, 7928, 772, 562, 775, 7822, 776, 376, 777, 7926, + 803, 7924, 769, 377, 770, 7824, 775, 379, 780, 381, 803, + 7826, 817, 7828, 768, 224, 769, 225, 770, 226, 771, 227, + 772, 257, 774, 259, 775, 551, 776, 228, 777, 7843, 778, + 229, 780, 462, 783, 513, 785, 515, 803, 7841, 805, 7681, + 808, 261, 775, 7683, 803, 7685, 817, 7687, 769, 263, 770, + 265, 775, 267, 780, 269, 807, 231, 775, 7691, 780, 271, + 803, 7693, 807, 7697, 813, 7699, 817, 7695, 768, 232, 769, + 233, 770, 234, 771, 7869, 772, 275, 774, 277, 775, 279, + 776, 235, 777, 7867, 780, 283, 783, 517, 785, 519, 803, + 7865, 807, 553, 808, 281, 813, 7705, 816, 7707, 775, 7711, + 769, 501, 770, 285, 772, 7713, 774, 287, 775, 289, 780, + 487, 807, 291, 770, 293, 775, 7715, 776, 7719, 780, 543, + 803, 7717, 807, 7721, 814, 7723, 817, 7830, 768, 236, 769, + 237, 770, 238, 771, 297, 772, 299, 774, 301, 776, 239, + 777, 7881, 780, 464, 783, 521, 785, 523, 803, 7883, 808, + 303, 816, 7725, 770, 309, 780, 496, 769, 7729, 780, 489, + 803, 7731, 807, 311, 817, 7733, 769, 314, 780, 318, 803, + 7735, 807, 316, 813, 7741, 817, 7739, 769, 7743, 775, 7745, + 803, 7747, 768, 505, 769, 324, 771, 241, 775, 7749, 780, + 328, 803, 7751, 807, 326, 813, 7755, 817, 7753, 768, 242, + 769, 243, 770, 244, 771, 245, 772, 333, 774, 335, 775, + 559, 776, 246, 777, 7887, 779, 337, 780, 466, 783, 525, + 785, 527, 795, 417, 803, 7885, 808, 491, 769, 7765, 775, + 7767, 769, 341, 775, 7769, 780, 345, 783, 529, 785, 531, + 803, 7771, 807, 343, 817, 7775, 769, 347, 770, 349, 775, + 7777, 780, 353, 803, 7779, 806, 537, 807, 351, 775, 7787, + 776, 7831, 780, 357, 803, 7789, 806, 539, 807, 355, 813, + 7793, 817, 7791, 768, 249, 769, 250, 770, 251, 771, 361, + 772, 363, 774, 365, 776, 252, 777, 7911, 778, 367, 779, + 369, 780, 468, 783, 533, 785, 535, 795, 432, 803, 7909, + 804, 7795, 808, 371, 813, 7799, 816, 7797, 771, 7805, 803, + 7807, 768, 7809, 769, 7811, 770, 373, 775, 7815, 776, 7813, + 778, 7832, 803, 7817, 775, 7819, 776, 7821, 768, 7923, 769, + 253, 770, 375, 771, 7929, 772, 563, 775, 7823, 776, 255, + 777, 7927, 778, 7833, 803, 7925, 769, 378, 770, 7825, 775, + 380, 780, 382, 803, 7827, 817, 7829, 768, 8173, 769, 901, + 834, 8129, 768, 7846, 769, 7844, 771, 7850, 777, 7848, 772, + 478, 769, 506, 769, 508, 772, 482, 769, 7688, 768, 7872, + 769, 7870, 771, 7876, 777, 7874, 769, 7726, 768, 7890, 769, + 7888, 771, 7894, 777, 7892, 769, 7756, 772, 556, 776, 7758, + 772, 554, 769, 510, 768, 475, 769, 471, 772, 469, 780, + 473, 768, 7847, 769, 7845, 771, 7851, 777, 7849, 772, 479, + 769, 507, 769, 509, 772, 483, 769, 7689, 768, 7873, 769, + 7871, 771, 7877, 777, 7875, 769, 7727, 768, 7891, 769, 7889, + 771, 7895, 777, 7893, 769, 7757, 772, 557, 776, 7759, 772, + 555, 769, 511, 768, 476, 769, 472, 772, 470, 780, 474, + 768, 7856, 769, 7854, 771, 7860, 777, 7858, 768, 7857, 769, + 7855, 771, 7861, 777, 7859, 768, 7700, 769, 7702, 768, 7701, + 769, 7703, 768, 7760, 769, 7762, 768, 7761, 769, 7763, 775, + 7780, 775, 7781, 775, 7782, 775, 7783, 769, 7800, 769, 7801, + 776, 7802, 776, 7803, 775, 7835, 768, 7900, 769, 7898, 771, + 7904, 777, 7902, 803, 7906, 768, 7901, 769, 7899, 771, 7905, + 777, 7903, 803, 7907, 768, 7914, 769, 7912, 771, 7918, 777, + 7916, 803, 7920, 768, 7915, 769, 7913, 771, 7919, 777, 7917, + 803, 7921, 780, 494, 772, 492, 772, 493, 772, 480, 772, + 481, 774, 7708, 774, 7709, 772, 560, 772, 561, 780, 495, + 768, 8122, 769, 902, 772, 8121, 774, 8120, 787, 7944, 788, + 7945, 837, 8124, 768, 8136, 769, 904, 787, 7960, 788, 7961, + 768, 8138, 769, 905, 787, 7976, 788, 7977, 837, 8140, 768, + 8154, 769, 906, 772, 8153, 774, 8152, 776, 938, 787, 7992, + 788, 7993, 768, 8184, 769, 908, 787, 8008, 788, 8009, 788, + 8172, 768, 8170, 769, 910, 772, 8169, 774, 8168, 776, 939, + 788, 8025, 768, 8186, 769, 911, 787, 8040, 788, 8041, 837, + 8188, 837, 8116, 837, 8132, 768, 8048, 769, 940, 772, 8113, + 774, 8112, 787, 7936, 788, 7937, 834, 8118, 837, 8115, 768, + 8050, 769, 941, 787, 7952, 788, 7953, 768, 8052, 769, 942, + 787, 7968, 788, 7969, 834, 8134, 837, 8131, 768, 8054, 769, + 943, 772, 8145, 774, 8144, 776, 970, 787, 7984, 788, 7985, + 834, 8150, 768, 8056, 769, 972, 787, 8000, 788, 8001, 787, + 8164, 788, 8165, 768, 8058, 769, 973, 772, 8161, 774, 8160, + 776, 971, 787, 8016, 788, 8017, 834, 8166, 768, 8060, 769, + 974, 787, 8032, 788, 8033, 834, 8182, 837, 8179, 768, 8146, + 769, 912, 834, 8151, 768, 8162, 769, 944, 834, 8167, 837, + 8180, 769, 979, 776, 980, 776, 1031, 774, 1232, 776, 1234, + 769, 1027, 768, 1024, 774, 1238, 776, 1025, 774, 1217, 776, + 1244, 776, 1246, 768, 1037, 772, 1250, 774, 1049, 776, 1252, + 769, 1036, 776, 1254, 772, 1262, 774, 1038, 776, 1264, 779, + 1266, 776, 1268, 776, 1272, 776, 1260, 774, 1233, 776, 1235, + 769, 1107, 768, 1104, 774, 1239, 776, 1105, 774, 1218, 776, + 1245, 776, 1247, 768, 1117, 772, 1251, 774, 1081, 776, 1253, + 769, 1116, 776, 1255, 772, 1263, 774, 1118, 776, 1265, 779, + 1267, 776, 1269, 776, 1273, 776, 1261, 776, 1111, 783, 1142, + 783, 1143, 776, 1242, 776, 1243, 776, 1258, 776, 1259, 1619, + 1570, 1620, 1571, 1621, 1573, 1620, 1572, 1620, 1574, 1620, 1730, + 1620, 1747, 1620, 1728, 2364, 2345, 2364, 2353, 2364, 2356, 2494, + 2507, 2519, 2508, 2878, 2891, 2902, 2888, 2903, 2892, 3031, 2964, + 3006, 3018, 3031, 3020, 3006, 3019, 3158, 3144, 3285, 3264, 3266, + 3274, 3285, 3271, 3286, 3272, 3285, 3275, 3390, 3402, 3415, 3404, + 3390, 3403, 3530, 3546, 3535, 3548, 3551, 3550, 3530, 3549, 4142, + 4134, 6965, 6918, 6965, 6920, 6965, 6922, 6965, 6924, 6965, 6926, + 6965, 6930, 6965, 6971, 6965, 6973, 6965, 6976, 6965, 6977, 6965, + 6979, 772, 7736, 772, 7737, 772, 7772, 772, 7773, 775, 7784, + 775, 7785, 770, 7852, 774, 7862, 770, 7853, 774, 7863, 770, + 7878, 770, 7879, 770, 7896, 770, 7897, 768, 7938, 769, 7940, + 834, 7942, 837, 8064, 768, 7939, 769, 7941, 834, 7943, 837, + 8065, 837, 8066, 837, 8067, 837, 8068, 837, 8069, 837, 8070, + 837, 8071, 768, 7946, 769, 7948, 834, 7950, 837, 8072, 768, + 7947, 769, 7949, 834, 7951, 837, 8073, 837, 8074, 837, 8075, + 837, 8076, 837, 8077, 837, 8078, 837, 8079, 768, 7954, 769, + 7956, 768, 7955, 769, 7957, 768, 7962, 769, 7964, 768, 7963, + 769, 7965, 768, 7970, 769, 7972, 834, 7974, 837, 8080, 768, + 7971, 769, 7973, 834, 7975, 837, 8081, 837, 8082, 837, 8083, + 837, 8084, 837, 8085, 837, 8086, 837, 8087, 768, 7978, 769, + 7980, 834, 7982, 837, 8088, 768, 7979, 769, 7981, 834, 7983, + 837, 8089, 837, 8090, 837, 8091, 837, 8092, 837, 8093, 837, + 8094, 837, 8095, 768, 7986, 769, 7988, 834, 7990, 768, 7987, + 769, 7989, 834, 7991, 768, 7994, 769, 7996, 834, 7998, 768, + 7995, 769, 7997, 834, 7999, 768, 8002, 769, 8004, 768, 8003, + 769, 8005, 768, 8010, 769, 8012, 768, 8011, 769, 8013, 768, + 8018, 769, 8020, 834, 8022, 768, 8019, 769, 8021, 834, 8023, + 768, 8027, 769, 8029, 834, 8031, 768, 8034, 769, 8036, 834, + 8038, 837, 8096, 768, 8035, 769, 8037, 834, 8039, 837, 8097, + 837, 8098, 837, 8099, 837, 8100, 837, 8101, 837, 8102, 837, + 8103, 768, 8042, 769, 8044, 834, 8046, 837, 8104, 768, 8043, + 769, 8045, 834, 8047, 837, 8105, 837, 8106, 837, 8107, 837, + 8108, 837, 8109, 837, 8110, 837, 8111, 837, 8114, 837, 8130, + 837, 8178, 837, 8119, 768, 8141, 769, 8142, 834, 8143, 837, + 8135, 837, 8183, 768, 8157, 769, 8158, 834, 8159, 824, 8602, + 824, 8603, 824, 8622, 824, 8653, 824, 8655, 824, 8654, 824, + 8708, 824, 8713, 824, 8716, 824, 8740, 824, 8742, 824, 8769, + 824, 8772, 824, 8775, 824, 8777, 824, 8813, 824, 8802, 824, + 8816, 824, 8817, 824, 8820, 824, 8821, 824, 8824, 824, 8825, + 824, 8832, 824, 8833, 824, 8928, 824, 8929, 824, 8836, 824, + 8837, 824, 8840, 824, 8841, 824, 8930, 824, 8931, 824, 8876, + 824, 8877, 824, 8878, 824, 8879, 824, 8938, 824, 8939, 824, + 8940, 824, 8941, 12441, 12436, 12441, 12364, 12441, 12366, 12441, 12368, + 12441, 12370, 12441, 12372, 12441, 12374, 12441, 12376, 12441, 12378, 12441, + 12380, 12441, 12382, 12441, 12384, 12441, 12386, 12441, 12389, 12441, 12391, + 12441, 12393, 12441, 12400, 12442, 12401, 12441, 12403, 12442, 12404, 12441, + 12406, 12442, 12407, 12441, 12409, 12442, 12410, 12441, 12412, 12442, 12413, + 12441, 12446, 12441, 12532, 12441, 12460, 12441, 12462, 12441, 12464, 12441, + 12466, 12441, 12468, 12441, 12470, 12441, 12472, 12441, 12474, 12441, 12476, + 12441, 12478, 12441, 12480, 12441, 12482, 12441, 12485, 12441, 12487, 12441, + 12489, 12441, 12496, 12442, 12497, 12441, 12499, 12442, 12500, 12441, 12502, + 12442, 12503, 12441, 12505, 12442, 12506, 12441, 12508, 12442, 12509, 12441, + 12535, 12441, 12536, 12441, 12537, 12441, 12538, 12441, 12542, 69818, 69786, + 69818, 69788, 69818, 69803, 69927, 69934, 69927, 69935, 70462, 70475, 70487, + 70476, 70832, 70844, 70842, 70843, 70845, 70846, 71087, 71098, 71087, 71099, + 71984, 71992}; + +} // namespace ada::idna +#endif // ADA_IDNA_NORMALIZATION_TABLES_H +/* end file src/normalization_tables.cpp */ + +namespace ada::idna { + +// See +// https://github.com/uni-algo/uni-algo/blob/c612968c5ed3ace39bde4c894c24286c5f2c7fe2/include/uni_algo/impl/impl_norm.h#L467 +constexpr char32_t hangul_sbase = 0xAC00; +constexpr char32_t hangul_tbase = 0x11A7; +constexpr char32_t hangul_vbase = 0x1161; +constexpr char32_t hangul_lbase = 0x1100; +constexpr char32_t hangul_lcount = 19; +constexpr char32_t hangul_vcount = 21; +constexpr char32_t hangul_tcount = 28; +constexpr char32_t hangul_ncount = hangul_vcount * hangul_tcount; +constexpr char32_t hangul_scount = + hangul_lcount * hangul_vcount * hangul_tcount; + +std::pair compute_decomposition_length( + const std::u32string_view input) noexcept { + bool decomposition_needed{false}; + size_t additional_elements{0}; + for (char32_t current_character : input) { + size_t decomposition_length{0}; + + if (current_character >= hangul_sbase && + current_character < hangul_sbase + hangul_scount) { + decomposition_length = 2; + if ((current_character - hangul_sbase) % hangul_tcount) { + decomposition_length = 3; + } + } else if (current_character < 0x110000) { + const uint8_t di = decomposition_index[current_character >> 8]; + const uint16_t* const decomposition = + decomposition_block[di] + (current_character % 256); + decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2); + if ((decomposition_length > 0) && (decomposition[0] & 1)) { + decomposition_length = 0; + } + } + if (decomposition_length != 0) { + decomposition_needed = true; + additional_elements += decomposition_length - 1; + } + } + return {decomposition_needed, additional_elements}; +} + +void decompose(std::u32string& input, size_t additional_elements) { + input.resize(input.size() + additional_elements); + for (size_t descending_idx = input.size(), + input_count = descending_idx - additional_elements; + input_count--;) { + if (input[input_count] >= hangul_sbase && + input[input_count] < hangul_sbase + hangul_scount) { + // Hangul decomposition. + char32_t s_index = input[input_count] - hangul_sbase; + if (s_index % hangul_tcount != 0) { + input[--descending_idx] = hangul_tbase + s_index % hangul_tcount; + } + input[--descending_idx] = + hangul_vbase + (s_index % hangul_ncount) / hangul_tcount; + input[--descending_idx] = hangul_lbase + s_index / hangul_ncount; + } else if (input[input_count] < 0x110000) { + // Check decomposition_data. + const uint16_t* decomposition = + decomposition_block[decomposition_index[input[input_count] >> 8]] + + (input[input_count] % 256); + uint16_t decomposition_length = + (decomposition[1] >> 2) - (decomposition[0] >> 2); + if (decomposition_length > 0 && (decomposition[0] & 1)) { + decomposition_length = 0; + } + if (decomposition_length > 0) { + // Non-recursive decomposition. + while (decomposition_length-- > 0) { + input[--descending_idx] = decomposition_data[(decomposition[0] >> 2) + + decomposition_length]; + } + } else { + // No decomposition. + input[--descending_idx] = input[input_count]; + } + } else { + // Non-Unicode character. + input[--descending_idx] = input[input_count]; + } + } +} + +uint8_t get_ccc(char32_t c) noexcept { + return c < 0x110000 ? canonical_combining_class_block + [canonical_combining_class_index[c >> 8]][c % 256] + : 0; +} + +void sort_marks(std::u32string& input) { + for (size_t idx = 1; idx < input.size(); idx++) { + uint8_t ccc = get_ccc(input[idx]); + if (ccc == 0) { + continue; + } // Skip non-combining characters. + auto current_character = input[idx]; + size_t back_idx = idx; + while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) { + input[back_idx] = input[back_idx - 1]; + back_idx--; + } + input[back_idx] = current_character; + } +} + +void decompose_nfc(std::u32string& input) { + /** + * Decompose the domain_name string to Unicode Normalization Form C. + * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose + */ + auto [decomposition_needed, additional_elements] = + compute_decomposition_length(input); + if (decomposition_needed) { + decompose(input, additional_elements); + } + sort_marks(input); +} + +void compose(std::u32string& input) { + /** + * Compose the domain_name string to Unicode Normalization Form C. + * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose + */ + size_t input_count{0}; + size_t composition_count{0}; + for (; input_count < input.size(); input_count++, composition_count++) { + input[composition_count] = input[input_count]; + if (input[input_count] >= hangul_lbase && + input[input_count] < hangul_lbase + hangul_lcount) { + if (input_count + 1 < input.size() && + input[input_count + 1] >= hangul_vbase && + input[input_count + 1] < hangul_vbase + hangul_vcount) { + input[composition_count] = + hangul_sbase + + ((input[input_count] - hangul_lbase) * hangul_vcount + + input[input_count + 1] - hangul_vbase) * + hangul_tcount; + input_count++; + if (input_count + 1 < input.size() && + input[input_count + 1] > hangul_tbase && + input[input_count + 1] < hangul_tbase + hangul_tcount) { + input[composition_count] += input[++input_count] - hangul_tbase; + } + } + } else if (input[input_count] >= hangul_sbase && + input[input_count] < hangul_sbase + hangul_scount) { + if ((input[input_count] - hangul_sbase) % hangul_tcount && + input_count + 1 < input.size() && + input[input_count + 1] > hangul_tbase && + input[input_count + 1] < hangul_tbase + hangul_tcount) { + input[composition_count] += input[++input_count] - hangul_tbase; + } + } else if (input[input_count] < 0x110000) { + const uint16_t* composition = + &composition_block[composition_index[input[input_count] >> 8]] + [input[input_count] % 256]; + size_t initial_composition_count = composition_count; + for (int32_t previous_ccc = -1; input_count + 1 < input.size(); + input_count++) { + uint8_t ccc = get_ccc(input[input_count + 1]); + + if (composition[1] != composition[0] && previous_ccc < ccc) { + // Try finding a composition. + uint16_t left = composition[0]; + uint16_t right = composition[1]; + while (left + 2 < right) { + // mean without overflow + uint16_t middle = left + (((right - left) >> 1) & ~1); + if (composition_data[middle] <= input[input_count + 1]) { + left = middle; + } + if (composition_data[middle] >= input[input_count + 1]) { + right = middle; + } + } + if (composition_data[left] == input[input_count + 1]) { + input[initial_composition_count] = composition_data[left + 1]; + composition = + &composition_block + [composition_index[composition_data[left + 1] >> 8]] + [composition_data[left + 1] % 256]; + continue; + } + } + + if (ccc == 0) { + break; + } // Not a combining character. + previous_ccc = ccc; + input[++composition_count] = input[input_count + 1]; + } + } + } + + if (composition_count < input_count) { + input.resize(composition_count); + } +} + +void normalize(std::u32string& input) { + /** + * Normalize the domain_name string to Unicode Normalization Form C. + * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize + */ + decompose_nfc(input); + compose(input); +} + +} // namespace ada::idna +/* end file src/normalization.cpp */ +/* begin file src/punycode.cpp */ + +#include + +namespace ada::idna { + +constexpr int32_t base = 36; +constexpr int32_t tmin = 1; +constexpr int32_t tmax = 26; +constexpr int32_t skew = 38; +constexpr int32_t damp = 700; +constexpr int32_t initial_bias = 72; +constexpr uint32_t initial_n = 128; + +static constexpr int32_t char_to_digit_value(char value) { + if (value >= 'a' && value <= 'z') return value - 'a'; + if (value >= '0' && value <= '9') return value - '0' + 26; + return -1; +} + +static constexpr char digit_to_char(int32_t digit) { + return digit < 26 ? char(digit + 97) : char(digit + 22); +} + +static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) { + if (firsttime) { + d = d / damp; + } else { + d = d / 2; + } + d += d / n; + int32_t k = 0; + while (d > ((base - tmin) * tmax) / 2) { + d /= base - tmin; + k += base; + } + return k + (((base - tmin + 1) * d) / (d + skew)); +} + +bool punycode_to_utf32(std::string_view input, std::u32string &out) { + int32_t written_out{0}; + out.reserve(out.size() + input.size()); + uint32_t n = initial_n; + int32_t i = 0; + int32_t bias = initial_bias; + // grab ascii content + size_t end_of_ascii = input.find_last_of('-'); + if (end_of_ascii != std::string_view::npos) { + for (uint8_t c : input.substr(0, end_of_ascii)) { + if (c >= 0x80) { + return false; + } + out.push_back(c); + written_out++; + } + input.remove_prefix(end_of_ascii + 1); + } + while (!input.empty()) { + int32_t oldi = i; + int32_t w = 1; + for (int32_t k = base;; k += base) { + if (input.empty()) { + return false; + } + uint8_t code_point = input.front(); + input.remove_prefix(1); + int32_t digit = char_to_digit_value(code_point); + if (digit < 0) { + return false; + } + if (digit > (0x7fffffff - i) / w) { + return false; + } + i = i + digit * w; + int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; + if (digit < t) { + break; + } + if (w > 0x7fffffff / (base - t)) { + return false; + } + w = w * (base - t); + } + bias = adapt(i - oldi, written_out + 1, oldi == 0); + if (i / (written_out + 1) > int32_t(0x7fffffff - n)) { + return false; + } + n = n + i / (written_out + 1); + i = i % (written_out + 1); + if (n < 0x80) { + return false; + } + out.insert(out.begin() + i, n); + written_out++; + ++i; + } + + return true; +} + +bool verify_punycode(std::string_view input) { + size_t written_out{0}; + uint32_t n = initial_n; + int32_t i = 0; + int32_t bias = initial_bias; + // grab ascii content + size_t end_of_ascii = input.find_last_of('-'); + if (end_of_ascii != std::string_view::npos) { + for (uint8_t c : input.substr(0, end_of_ascii)) { + if (c >= 0x80) { + return false; + } + written_out++; + } + input.remove_prefix(end_of_ascii + 1); + } + while (!input.empty()) { + int32_t oldi = i; + int32_t w = 1; + for (int32_t k = base;; k += base) { + if (input.empty()) { + return false; + } + uint8_t code_point = input.front(); + input.remove_prefix(1); + int32_t digit = char_to_digit_value(code_point); + if (digit < 0) { + return false; + } + if (digit > (0x7fffffff - i) / w) { + return false; + } + i = i + digit * w; + int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; + if (digit < t) { + break; + } + if (w > 0x7fffffff / (base - t)) { + return false; + } + w = w * (base - t); + } + bias = adapt(i - oldi, int32_t(written_out + 1), oldi == 0); + if (i / (written_out + 1) > 0x7fffffff - n) { + return false; + } + n = n + i / int32_t(written_out + 1); + i = i % int32_t(written_out + 1); + if (n < 0x80) { + return false; + } + written_out++; + ++i; + } + + return true; +} + +bool utf32_to_punycode(std::u32string_view input, std::string &out) { + out.reserve(input.size() + out.size()); + uint32_t n = initial_n; + int32_t d = 0; + int32_t bias = initial_bias; + size_t h = 0; + // first push the ascii content + for (uint32_t c : input) { + if (c < 0x80) { + ++h; + out.push_back(char(c)); + } + if (c > 0x10ffff || (c >= 0xd880 && c < 0xe000)) { + return false; + } + } + size_t b = h; + if (b > 0) { + out.push_back('-'); + } + while (h < input.size()) { + uint32_t m = 0x10FFFF; + for (auto code_point : input) { + if (code_point >= n && code_point < m) m = code_point; + } + + if ((m - n) > (0x7fffffff - d) / (h + 1)) { + return false; + } + d = d + int32_t((m - n) * (h + 1)); + n = m; + for (auto c : input) { + if (c < n) { + if (d == 0x7fffffff) { + return false; + } + ++d; + } + if (c == n) { + int32_t q = d; + for (int32_t k = base;; k += base) { + int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; + + if (q < t) { + break; + } + out.push_back(digit_to_char(t + ((q - t) % (base - t)))); + q = (q - t) / (base - t); + } + out.push_back(digit_to_char(q)); + bias = adapt(d, int32_t(h + 1), h == b); + d = 0; + ++h; + } + } + ++d; + ++n; + } + return true; +} + +} // namespace ada::idna +/* end file src/punycode.cpp */ +/* begin file src/validity.cpp */ +#include +#include + +namespace ada::idna { + +enum direction : uint8_t { + NONE, + BN, + CS, + ES, + ON, + EN, + L, + R, + NSM, + AL, + AN, + ET, + WS, + RLO, + LRO, + PDF, + RLE, + RLI, + FSI, + PDI, + LRI, + B, + S, + LRE +}; + +struct directions { + uint32_t start_code; + uint32_t final_code; + direction direct; +}; + +static directions dir_table[] = { + {0x0, 0x8, direction::BN}, {0x9, 0x9, direction::S}, + {0xa, 0xa, direction::B}, {0xb, 0xb, direction::S}, + {0xc, 0xc, direction::WS}, {0xd, 0xd, direction::B}, + {0xe, 0x1b, direction::BN}, {0x1c, 0x1e, direction::B}, + {0x1f, 0x1f, direction::S}, {0x20, 0x20, direction::WS}, + {0x21, 0x22, direction::ON}, {0x23, 0x25, direction::ET}, + {0x26, 0x2a, direction::ON}, {0x2b, 0x2b, direction::ES}, + {0x2c, 0x2c, direction::CS}, {0x2d, 0x2d, direction::ES}, + {0x2e, 0x2f, direction::CS}, {0x30, 0x39, direction::EN}, + {0x3a, 0x3a, direction::CS}, {0x3b, 0x40, direction::ON}, + {0x41, 0x5a, direction::L}, {0x5b, 0x60, direction::ON}, + {0x61, 0x7a, direction::L}, {0x7b, 0x7e, direction::ON}, + {0x7f, 0x84, direction::BN}, {0x85, 0x85, direction::B}, + {0x86, 0x9f, direction::BN}, {0xa0, 0xa0, direction::CS}, + {0xa1, 0xa1, direction::ON}, {0xa2, 0xa5, direction::ET}, + {0xa6, 0xa9, direction::ON}, {0xaa, 0xaa, direction::L}, + {0xab, 0xac, direction::ON}, {0xad, 0xad, direction::BN}, + {0xae, 0xaf, direction::ON}, {0xb0, 0xb1, direction::ET}, + {0xb2, 0xb3, direction::EN}, {0xb4, 0xb4, direction::ON}, + {0xb5, 0xb5, direction::L}, {0xb6, 0xb8, direction::ON}, + {0xb9, 0xb9, direction::EN}, {0xba, 0xba, direction::L}, + {0xbb, 0xbf, direction::ON}, {0xc0, 0xd6, direction::L}, + {0xd7, 0xd7, direction::ON}, {0xd8, 0xf6, direction::L}, + {0xf7, 0xf7, direction::ON}, {0xf8, 0x2b8, direction::L}, + {0x2b9, 0x2ba, direction::ON}, {0x2bb, 0x2c1, direction::L}, + {0x2c2, 0x2cf, direction::ON}, {0x2d0, 0x2d1, direction::L}, + {0x2d2, 0x2df, direction::ON}, {0x2e0, 0x2e4, direction::L}, + {0x2e5, 0x2ed, direction::ON}, {0x2ee, 0x2ee, direction::L}, + {0x2ef, 0x2ff, direction::ON}, {0x300, 0x36f, direction::NSM}, + {0x370, 0x373, direction::L}, {0x374, 0x375, direction::ON}, + {0x376, 0x377, direction::L}, {0x37a, 0x37d, direction::L}, + {0x37e, 0x37e, direction::ON}, {0x37f, 0x37f, direction::L}, + {0x384, 0x385, direction::ON}, {0x386, 0x386, direction::L}, + {0x387, 0x387, direction::ON}, {0x388, 0x38a, direction::L}, + {0x38c, 0x38c, direction::L}, {0x38e, 0x3a1, direction::L}, + {0x3a3, 0x3f5, direction::L}, {0x3f6, 0x3f6, direction::ON}, + {0x3f7, 0x482, direction::L}, {0x483, 0x489, direction::NSM}, + {0x48a, 0x52f, direction::L}, {0x531, 0x556, direction::L}, + {0x559, 0x589, direction::L}, {0x58a, 0x58a, direction::ON}, + {0x58d, 0x58e, direction::ON}, {0x58f, 0x58f, direction::ET}, + {0x591, 0x5bd, direction::NSM}, {0x5be, 0x5be, direction::R}, + {0x5bf, 0x5bf, direction::NSM}, {0x5c0, 0x5c0, direction::R}, + {0x5c1, 0x5c2, direction::NSM}, {0x5c3, 0x5c3, direction::R}, + {0x5c4, 0x5c5, direction::NSM}, {0x5c6, 0x5c6, direction::R}, + {0x5c7, 0x5c7, direction::NSM}, {0x5d0, 0x5ea, direction::R}, + {0x5ef, 0x5f4, direction::R}, {0x600, 0x605, direction::AN}, + {0x606, 0x607, direction::ON}, {0x608, 0x608, direction::AL}, + {0x609, 0x60a, direction::ET}, {0x60b, 0x60b, direction::AL}, + {0x60c, 0x60c, direction::CS}, {0x60d, 0x60d, direction::AL}, + {0x60e, 0x60f, direction::ON}, {0x610, 0x61a, direction::NSM}, + {0x61b, 0x61c, direction::AL}, {0x61e, 0x64a, direction::AL}, + {0x64b, 0x65f, direction::NSM}, {0x660, 0x669, direction::AN}, + {0x66a, 0x66a, direction::ET}, {0x66b, 0x66c, direction::AN}, + {0x66d, 0x66f, direction::AL}, {0x670, 0x670, direction::NSM}, + {0x671, 0x6d5, direction::AL}, {0x6d6, 0x6dc, direction::NSM}, + {0x6dd, 0x6dd, direction::AN}, {0x6de, 0x6de, direction::ON}, + {0x6df, 0x6e4, direction::NSM}, {0x6e5, 0x6e6, direction::AL}, + {0x6e7, 0x6e8, direction::NSM}, {0x6e9, 0x6e9, direction::ON}, + {0x6ea, 0x6ed, direction::NSM}, {0x6ee, 0x6ef, direction::AL}, + {0x6f0, 0x6f9, direction::EN}, {0x6fa, 0x70d, direction::AL}, + {0x70f, 0x710, direction::AL}, {0x711, 0x711, direction::NSM}, + {0x712, 0x72f, direction::AL}, {0x730, 0x74a, direction::NSM}, + {0x74d, 0x7a5, direction::AL}, {0x7a6, 0x7b0, direction::NSM}, + {0x7b1, 0x7b1, direction::AL}, {0x7c0, 0x7ea, direction::R}, + {0x7eb, 0x7f3, direction::NSM}, {0x7f4, 0x7f5, direction::R}, + {0x7f6, 0x7f9, direction::ON}, {0x7fa, 0x7fa, direction::R}, + {0x7fd, 0x7fd, direction::NSM}, {0x7fe, 0x815, direction::R}, + {0x816, 0x819, direction::NSM}, {0x81a, 0x81a, direction::R}, + {0x81b, 0x823, direction::NSM}, {0x824, 0x824, direction::R}, + {0x825, 0x827, direction::NSM}, {0x828, 0x828, direction::R}, + {0x829, 0x82d, direction::NSM}, {0x830, 0x83e, direction::R}, + {0x840, 0x858, direction::R}, {0x859, 0x85b, direction::NSM}, + {0x85e, 0x85e, direction::R}, {0x860, 0x86a, direction::AL}, + {0x8a0, 0x8b4, direction::AL}, {0x8b6, 0x8c7, direction::AL}, + {0x8d3, 0x8e1, direction::NSM}, {0x8e2, 0x8e2, direction::AN}, + {0x8e3, 0x902, direction::NSM}, {0x903, 0x939, direction::L}, + {0x93a, 0x93a, direction::NSM}, {0x93b, 0x93b, direction::L}, + {0x93c, 0x93c, direction::NSM}, {0x93d, 0x940, direction::L}, + {0x941, 0x948, direction::NSM}, {0x949, 0x94c, direction::L}, + {0x94d, 0x94d, direction::NSM}, {0x94e, 0x950, direction::L}, + {0x951, 0x957, direction::NSM}, {0x958, 0x961, direction::L}, + {0x962, 0x963, direction::NSM}, {0x964, 0x980, direction::L}, + {0x981, 0x981, direction::NSM}, {0x982, 0x983, direction::L}, + {0x985, 0x98c, direction::L}, {0x98f, 0x990, direction::L}, + {0x993, 0x9a8, direction::L}, {0x9aa, 0x9b0, direction::L}, + {0x9b2, 0x9b2, direction::L}, {0x9b6, 0x9b9, direction::L}, + {0x9bc, 0x9bc, direction::NSM}, {0x9bd, 0x9c0, direction::L}, + {0x9c1, 0x9c4, direction::NSM}, {0x9c7, 0x9c8, direction::L}, + {0x9cb, 0x9cc, direction::L}, {0x9cd, 0x9cd, direction::NSM}, + {0x9ce, 0x9ce, direction::L}, {0x9d7, 0x9d7, direction::L}, + {0x9dc, 0x9dd, direction::L}, {0x9df, 0x9e1, direction::L}, + {0x9e2, 0x9e3, direction::NSM}, {0x9e6, 0x9f1, direction::L}, + {0x9f2, 0x9f3, direction::ET}, {0x9f4, 0x9fa, direction::L}, + {0x9fb, 0x9fb, direction::ET}, {0x9fc, 0x9fd, direction::L}, + {0x9fe, 0x9fe, direction::NSM}, {0xa01, 0xa02, direction::NSM}, + {0xa03, 0xa03, direction::L}, {0xa05, 0xa0a, direction::L}, + {0xa0f, 0xa10, direction::L}, {0xa13, 0xa28, direction::L}, + {0xa2a, 0xa30, direction::L}, {0xa32, 0xa33, direction::L}, + {0xa35, 0xa36, direction::L}, {0xa38, 0xa39, direction::L}, + {0xa3c, 0xa3c, direction::NSM}, {0xa3e, 0xa40, direction::L}, + {0xa41, 0xa42, direction::NSM}, {0xa47, 0xa48, direction::NSM}, + {0xa4b, 0xa4d, direction::NSM}, {0xa51, 0xa51, direction::NSM}, + {0xa59, 0xa5c, direction::L}, {0xa5e, 0xa5e, direction::L}, + {0xa66, 0xa6f, direction::L}, {0xa70, 0xa71, direction::NSM}, + {0xa72, 0xa74, direction::L}, {0xa75, 0xa75, direction::NSM}, + {0xa76, 0xa76, direction::L}, {0xa81, 0xa82, direction::NSM}, + {0xa83, 0xa83, direction::L}, {0xa85, 0xa8d, direction::L}, + {0xa8f, 0xa91, direction::L}, {0xa93, 0xaa8, direction::L}, + {0xaaa, 0xab0, direction::L}, {0xab2, 0xab3, direction::L}, + {0xab5, 0xab9, direction::L}, {0xabc, 0xabc, direction::NSM}, + {0xabd, 0xac0, direction::L}, {0xac1, 0xac5, direction::NSM}, + {0xac7, 0xac8, direction::NSM}, {0xac9, 0xac9, direction::L}, + {0xacb, 0xacc, direction::L}, {0xacd, 0xacd, direction::NSM}, + {0xad0, 0xad0, direction::L}, {0xae0, 0xae1, direction::L}, + {0xae2, 0xae3, direction::NSM}, {0xae6, 0xaf0, direction::L}, + {0xaf1, 0xaf1, direction::ET}, {0xaf9, 0xaf9, direction::L}, + {0xafa, 0xaff, direction::NSM}, {0xb01, 0xb01, direction::NSM}, + {0xb02, 0xb03, direction::L}, {0xb05, 0xb0c, direction::L}, + {0xb0f, 0xb10, direction::L}, {0xb13, 0xb28, direction::L}, + {0xb2a, 0xb30, direction::L}, {0xb32, 0xb33, direction::L}, + {0xb35, 0xb39, direction::L}, {0xb3c, 0xb3c, direction::NSM}, + {0xb3d, 0xb3e, direction::L}, {0xb3f, 0xb3f, direction::NSM}, + {0xb40, 0xb40, direction::L}, {0xb41, 0xb44, direction::NSM}, + {0xb47, 0xb48, direction::L}, {0xb4b, 0xb4c, direction::L}, + {0xb4d, 0xb4d, direction::NSM}, {0xb55, 0xb56, direction::NSM}, + {0xb57, 0xb57, direction::L}, {0xb5c, 0xb5d, direction::L}, + {0xb5f, 0xb61, direction::L}, {0xb62, 0xb63, direction::NSM}, + {0xb66, 0xb77, direction::L}, {0xb82, 0xb82, direction::NSM}, + {0xb83, 0xb83, direction::L}, {0xb85, 0xb8a, direction::L}, + {0xb8e, 0xb90, direction::L}, {0xb92, 0xb95, direction::L}, + {0xb99, 0xb9a, direction::L}, {0xb9c, 0xb9c, direction::L}, + {0xb9e, 0xb9f, direction::L}, {0xba3, 0xba4, direction::L}, + {0xba8, 0xbaa, direction::L}, {0xbae, 0xbb9, direction::L}, + {0xbbe, 0xbbf, direction::L}, {0xbc0, 0xbc0, direction::NSM}, + {0xbc1, 0xbc2, direction::L}, {0xbc6, 0xbc8, direction::L}, + {0xbca, 0xbcc, direction::L}, {0xbcd, 0xbcd, direction::NSM}, + {0xbd0, 0xbd0, direction::L}, {0xbd7, 0xbd7, direction::L}, + {0xbe6, 0xbf2, direction::L}, {0xbf3, 0xbf8, direction::ON}, + {0xbf9, 0xbf9, direction::ET}, {0xbfa, 0xbfa, direction::ON}, + {0xc00, 0xc00, direction::NSM}, {0xc01, 0xc03, direction::L}, + {0xc04, 0xc04, direction::NSM}, {0xc05, 0xc0c, direction::L}, + {0xc0e, 0xc10, direction::L}, {0xc12, 0xc28, direction::L}, + {0xc2a, 0xc39, direction::L}, {0xc3d, 0xc3d, direction::L}, + {0xc3e, 0xc40, direction::NSM}, {0xc41, 0xc44, direction::L}, + {0xc46, 0xc48, direction::NSM}, {0xc4a, 0xc4d, direction::NSM}, + {0xc55, 0xc56, direction::NSM}, {0xc58, 0xc5a, direction::L}, + {0xc60, 0xc61, direction::L}, {0xc62, 0xc63, direction::NSM}, + {0xc66, 0xc6f, direction::L}, {0xc77, 0xc77, direction::L}, + {0xc78, 0xc7e, direction::ON}, {0xc7f, 0xc80, direction::L}, + {0xc81, 0xc81, direction::NSM}, {0xc82, 0xc8c, direction::L}, + {0xc8e, 0xc90, direction::L}, {0xc92, 0xca8, direction::L}, + {0xcaa, 0xcb3, direction::L}, {0xcb5, 0xcb9, direction::L}, + {0xcbc, 0xcbc, direction::NSM}, {0xcbd, 0xcc4, direction::L}, + {0xcc6, 0xcc8, direction::L}, {0xcca, 0xccb, direction::L}, + {0xccc, 0xccd, direction::NSM}, {0xcd5, 0xcd6, direction::L}, + {0xcde, 0xcde, direction::L}, {0xce0, 0xce1, direction::L}, + {0xce2, 0xce3, direction::NSM}, {0xce6, 0xcef, direction::L}, + {0xcf1, 0xcf2, direction::L}, {0xd00, 0xd01, direction::NSM}, + {0xd02, 0xd0c, direction::L}, {0xd0e, 0xd10, direction::L}, + {0xd12, 0xd3a, direction::L}, {0xd3b, 0xd3c, direction::NSM}, + {0xd3d, 0xd40, direction::L}, {0xd41, 0xd44, direction::NSM}, + {0xd46, 0xd48, direction::L}, {0xd4a, 0xd4c, direction::L}, + {0xd4d, 0xd4d, direction::NSM}, {0xd4e, 0xd4f, direction::L}, + {0xd54, 0xd61, direction::L}, {0xd62, 0xd63, direction::NSM}, + {0xd66, 0xd7f, direction::L}, {0xd81, 0xd81, direction::NSM}, + {0xd82, 0xd83, direction::L}, {0xd85, 0xd96, direction::L}, + {0xd9a, 0xdb1, direction::L}, {0xdb3, 0xdbb, direction::L}, + {0xdbd, 0xdbd, direction::L}, {0xdc0, 0xdc6, direction::L}, + {0xdca, 0xdca, direction::NSM}, {0xdcf, 0xdd1, direction::L}, + {0xdd2, 0xdd4, direction::NSM}, {0xdd6, 0xdd6, direction::NSM}, + {0xdd8, 0xddf, direction::L}, {0xde6, 0xdef, direction::L}, + {0xdf2, 0xdf4, direction::L}, {0xe01, 0xe30, direction::L}, + {0xe31, 0xe31, direction::NSM}, {0xe32, 0xe33, direction::L}, + {0xe34, 0xe3a, direction::NSM}, {0xe3f, 0xe3f, direction::ET}, + {0xe40, 0xe46, direction::L}, {0xe47, 0xe4e, direction::NSM}, + {0xe4f, 0xe5b, direction::L}, {0xe81, 0xe82, direction::L}, + {0xe84, 0xe84, direction::L}, {0xe86, 0xe8a, direction::L}, + {0xe8c, 0xea3, direction::L}, {0xea5, 0xea5, direction::L}, + {0xea7, 0xeb0, direction::L}, {0xeb1, 0xeb1, direction::NSM}, + {0xeb2, 0xeb3, direction::L}, {0xeb4, 0xebc, direction::NSM}, + {0xebd, 0xebd, direction::L}, {0xec0, 0xec4, direction::L}, + {0xec6, 0xec6, direction::L}, {0xec8, 0xecd, direction::NSM}, + {0xed0, 0xed9, direction::L}, {0xedc, 0xedf, direction::L}, + {0xf00, 0xf17, direction::L}, {0xf18, 0xf19, direction::NSM}, + {0xf1a, 0xf34, direction::L}, {0xf35, 0xf35, direction::NSM}, + {0xf36, 0xf36, direction::L}, {0xf37, 0xf37, direction::NSM}, + {0xf38, 0xf38, direction::L}, {0xf39, 0xf39, direction::NSM}, + {0xf3a, 0xf3d, direction::ON}, {0xf3e, 0xf47, direction::L}, + {0xf49, 0xf6c, direction::L}, {0xf71, 0xf7e, direction::NSM}, + {0xf7f, 0xf7f, direction::L}, {0xf80, 0xf84, direction::NSM}, + {0xf85, 0xf85, direction::L}, {0xf86, 0xf87, direction::NSM}, + {0xf88, 0xf8c, direction::L}, {0xf8d, 0xf97, direction::NSM}, + {0xf99, 0xfbc, direction::NSM}, {0xfbe, 0xfc5, direction::L}, + {0xfc6, 0xfc6, direction::NSM}, {0xfc7, 0xfcc, direction::L}, + {0xfce, 0xfda, direction::L}, {0x1000, 0x102c, direction::L}, + {0x102d, 0x1030, direction::NSM}, {0x1031, 0x1031, direction::L}, + {0x1032, 0x1037, direction::NSM}, {0x1038, 0x1038, direction::L}, + {0x1039, 0x103a, direction::NSM}, {0x103b, 0x103c, direction::L}, + {0x103d, 0x103e, direction::NSM}, {0x103f, 0x1057, direction::L}, + {0x1058, 0x1059, direction::NSM}, {0x105a, 0x105d, direction::L}, + {0x105e, 0x1060, direction::NSM}, {0x1061, 0x1070, direction::L}, + {0x1071, 0x1074, direction::NSM}, {0x1075, 0x1081, direction::L}, + {0x1082, 0x1082, direction::NSM}, {0x1083, 0x1084, direction::L}, + {0x1085, 0x1086, direction::NSM}, {0x1087, 0x108c, direction::L}, + {0x108d, 0x108d, direction::NSM}, {0x108e, 0x109c, direction::L}, + {0x109d, 0x109d, direction::NSM}, {0x109e, 0x10c5, direction::L}, + {0x10c7, 0x10c7, direction::L}, {0x10cd, 0x10cd, direction::L}, + {0x10d0, 0x1248, direction::L}, {0x124a, 0x124d, direction::L}, + {0x1250, 0x1256, direction::L}, {0x1258, 0x1258, direction::L}, + {0x125a, 0x125d, direction::L}, {0x1260, 0x1288, direction::L}, + {0x128a, 0x128d, direction::L}, {0x1290, 0x12b0, direction::L}, + {0x12b2, 0x12b5, direction::L}, {0x12b8, 0x12be, direction::L}, + {0x12c0, 0x12c0, direction::L}, {0x12c2, 0x12c5, direction::L}, + {0x12c8, 0x12d6, direction::L}, {0x12d8, 0x1310, direction::L}, + {0x1312, 0x1315, direction::L}, {0x1318, 0x135a, direction::L}, + {0x135d, 0x135f, direction::NSM}, {0x1360, 0x137c, direction::L}, + {0x1380, 0x138f, direction::L}, {0x1390, 0x1399, direction::ON}, + {0x13a0, 0x13f5, direction::L}, {0x13f8, 0x13fd, direction::L}, + {0x1400, 0x1400, direction::ON}, {0x1401, 0x167f, direction::L}, + {0x1680, 0x1680, direction::WS}, {0x1681, 0x169a, direction::L}, + {0x169b, 0x169c, direction::ON}, {0x16a0, 0x16f8, direction::L}, + {0x1700, 0x170c, direction::L}, {0x170e, 0x1711, direction::L}, + {0x1712, 0x1714, direction::NSM}, {0x1720, 0x1731, direction::L}, + {0x1732, 0x1734, direction::NSM}, {0x1735, 0x1736, direction::L}, + {0x1740, 0x1751, direction::L}, {0x1752, 0x1753, direction::NSM}, + {0x1760, 0x176c, direction::L}, {0x176e, 0x1770, direction::L}, + {0x1772, 0x1773, direction::NSM}, {0x1780, 0x17b3, direction::L}, + {0x17b4, 0x17b5, direction::NSM}, {0x17b6, 0x17b6, direction::L}, + {0x17b7, 0x17bd, direction::NSM}, {0x17be, 0x17c5, direction::L}, + {0x17c6, 0x17c6, direction::NSM}, {0x17c7, 0x17c8, direction::L}, + {0x17c9, 0x17d3, direction::NSM}, {0x17d4, 0x17da, direction::L}, + {0x17db, 0x17db, direction::ET}, {0x17dc, 0x17dc, direction::L}, + {0x17dd, 0x17dd, direction::NSM}, {0x17e0, 0x17e9, direction::L}, + {0x17f0, 0x17f9, direction::ON}, {0x1800, 0x180a, direction::ON}, + {0x180b, 0x180d, direction::NSM}, {0x180e, 0x180e, direction::BN}, + {0x1810, 0x1819, direction::L}, {0x1820, 0x1878, direction::L}, + {0x1880, 0x1884, direction::L}, {0x1885, 0x1886, direction::NSM}, + {0x1887, 0x18a8, direction::L}, {0x18a9, 0x18a9, direction::NSM}, + {0x18aa, 0x18aa, direction::L}, {0x18b0, 0x18f5, direction::L}, + {0x1900, 0x191e, direction::L}, {0x1920, 0x1922, direction::NSM}, + {0x1923, 0x1926, direction::L}, {0x1927, 0x1928, direction::NSM}, + {0x1929, 0x192b, direction::L}, {0x1930, 0x1931, direction::L}, + {0x1932, 0x1932, direction::NSM}, {0x1933, 0x1938, direction::L}, + {0x1939, 0x193b, direction::NSM}, {0x1940, 0x1940, direction::ON}, + {0x1944, 0x1945, direction::ON}, {0x1946, 0x196d, direction::L}, + {0x1970, 0x1974, direction::L}, {0x1980, 0x19ab, direction::L}, + {0x19b0, 0x19c9, direction::L}, {0x19d0, 0x19da, direction::L}, + {0x19de, 0x19ff, direction::ON}, {0x1a00, 0x1a16, direction::L}, + {0x1a17, 0x1a18, direction::NSM}, {0x1a19, 0x1a1a, direction::L}, + {0x1a1b, 0x1a1b, direction::NSM}, {0x1a1e, 0x1a55, direction::L}, + {0x1a56, 0x1a56, direction::NSM}, {0x1a57, 0x1a57, direction::L}, + {0x1a58, 0x1a5e, direction::NSM}, {0x1a60, 0x1a60, direction::NSM}, + {0x1a61, 0x1a61, direction::L}, {0x1a62, 0x1a62, direction::NSM}, + {0x1a63, 0x1a64, direction::L}, {0x1a65, 0x1a6c, direction::NSM}, + {0x1a6d, 0x1a72, direction::L}, {0x1a73, 0x1a7c, direction::NSM}, + {0x1a7f, 0x1a7f, direction::NSM}, {0x1a80, 0x1a89, direction::L}, + {0x1a90, 0x1a99, direction::L}, {0x1aa0, 0x1aad, direction::L}, + {0x1ab0, 0x1ac0, direction::NSM}, {0x1b00, 0x1b03, direction::NSM}, + {0x1b04, 0x1b33, direction::L}, {0x1b34, 0x1b34, direction::NSM}, + {0x1b35, 0x1b35, direction::L}, {0x1b36, 0x1b3a, direction::NSM}, + {0x1b3b, 0x1b3b, direction::L}, {0x1b3c, 0x1b3c, direction::NSM}, + {0x1b3d, 0x1b41, direction::L}, {0x1b42, 0x1b42, direction::NSM}, + {0x1b43, 0x1b4b, direction::L}, {0x1b50, 0x1b6a, direction::L}, + {0x1b6b, 0x1b73, direction::NSM}, {0x1b74, 0x1b7c, direction::L}, + {0x1b80, 0x1b81, direction::NSM}, {0x1b82, 0x1ba1, direction::L}, + {0x1ba2, 0x1ba5, direction::NSM}, {0x1ba6, 0x1ba7, direction::L}, + {0x1ba8, 0x1ba9, direction::NSM}, {0x1baa, 0x1baa, direction::L}, + {0x1bab, 0x1bad, direction::NSM}, {0x1bae, 0x1be5, direction::L}, + {0x1be6, 0x1be6, direction::NSM}, {0x1be7, 0x1be7, direction::L}, + {0x1be8, 0x1be9, direction::NSM}, {0x1bea, 0x1bec, direction::L}, + {0x1bed, 0x1bed, direction::NSM}, {0x1bee, 0x1bee, direction::L}, + {0x1bef, 0x1bf1, direction::NSM}, {0x1bf2, 0x1bf3, direction::L}, + {0x1bfc, 0x1c2b, direction::L}, {0x1c2c, 0x1c33, direction::NSM}, + {0x1c34, 0x1c35, direction::L}, {0x1c36, 0x1c37, direction::NSM}, + {0x1c3b, 0x1c49, direction::L}, {0x1c4d, 0x1c88, direction::L}, + {0x1c90, 0x1cba, direction::L}, {0x1cbd, 0x1cc7, direction::L}, + {0x1cd0, 0x1cd2, direction::NSM}, {0x1cd3, 0x1cd3, direction::L}, + {0x1cd4, 0x1ce0, direction::NSM}, {0x1ce1, 0x1ce1, direction::L}, + {0x1ce2, 0x1ce8, direction::NSM}, {0x1ce9, 0x1cec, direction::L}, + {0x1ced, 0x1ced, direction::NSM}, {0x1cee, 0x1cf3, direction::L}, + {0x1cf4, 0x1cf4, direction::NSM}, {0x1cf5, 0x1cf7, direction::L}, + {0x1cf8, 0x1cf9, direction::NSM}, {0x1cfa, 0x1cfa, direction::L}, + {0x1d00, 0x1dbf, direction::L}, {0x1dc0, 0x1df9, direction::NSM}, + {0x1dfb, 0x1dff, direction::NSM}, {0x1e00, 0x1f15, direction::L}, + {0x1f18, 0x1f1d, direction::L}, {0x1f20, 0x1f45, direction::L}, + {0x1f48, 0x1f4d, direction::L}, {0x1f50, 0x1f57, direction::L}, + {0x1f59, 0x1f59, direction::L}, {0x1f5b, 0x1f5b, direction::L}, + {0x1f5d, 0x1f5d, direction::L}, {0x1f5f, 0x1f7d, direction::L}, + {0x1f80, 0x1fb4, direction::L}, {0x1fb6, 0x1fbc, direction::L}, + {0x1fbd, 0x1fbd, direction::ON}, {0x1fbe, 0x1fbe, direction::L}, + {0x1fbf, 0x1fc1, direction::ON}, {0x1fc2, 0x1fc4, direction::L}, + {0x1fc6, 0x1fcc, direction::L}, {0x1fcd, 0x1fcf, direction::ON}, + {0x1fd0, 0x1fd3, direction::L}, {0x1fd6, 0x1fdb, direction::L}, + {0x1fdd, 0x1fdf, direction::ON}, {0x1fe0, 0x1fec, direction::L}, + {0x1fed, 0x1fef, direction::ON}, {0x1ff2, 0x1ff4, direction::L}, + {0x1ff6, 0x1ffc, direction::L}, {0x1ffd, 0x1ffe, direction::ON}, + {0x2000, 0x200a, direction::WS}, {0x200b, 0x200d, direction::BN}, + {0x200e, 0x200e, direction::L}, {0x200f, 0x200f, direction::R}, + {0x2010, 0x2027, direction::ON}, {0x2028, 0x2028, direction::WS}, + {0x2029, 0x2029, direction::B}, {0x202a, 0x202a, direction::LRE}, + {0x202b, 0x202b, direction::RLE}, {0x202c, 0x202c, direction::PDF}, + {0x202d, 0x202d, direction::LRO}, {0x202e, 0x202e, direction::RLO}, + {0x202f, 0x202f, direction::CS}, {0x2030, 0x2034, direction::ET}, + {0x2035, 0x2043, direction::ON}, {0x2044, 0x2044, direction::CS}, + {0x2045, 0x205e, direction::ON}, {0x205f, 0x205f, direction::WS}, + {0x2060, 0x2064, direction::BN}, {0x2066, 0x2066, direction::LRI}, + {0x2067, 0x2067, direction::RLI}, {0x2068, 0x2068, direction::FSI}, + {0x2069, 0x2069, direction::PDI}, {0x206a, 0x206f, direction::BN}, + {0x2070, 0x2070, direction::EN}, {0x2071, 0x2071, direction::L}, + {0x2074, 0x2079, direction::EN}, {0x207a, 0x207b, direction::ES}, + {0x207c, 0x207e, direction::ON}, {0x207f, 0x207f, direction::L}, + {0x2080, 0x2089, direction::EN}, {0x208a, 0x208b, direction::ES}, + {0x208c, 0x208e, direction::ON}, {0x2090, 0x209c, direction::L}, + {0x20a0, 0x20bf, direction::ET}, {0x20d0, 0x20f0, direction::NSM}, + {0x2100, 0x2101, direction::ON}, {0x2102, 0x2102, direction::L}, + {0x2103, 0x2106, direction::ON}, {0x2107, 0x2107, direction::L}, + {0x2108, 0x2109, direction::ON}, {0x210a, 0x2113, direction::L}, + {0x2114, 0x2114, direction::ON}, {0x2115, 0x2115, direction::L}, + {0x2116, 0x2118, direction::ON}, {0x2119, 0x211d, direction::L}, + {0x211e, 0x2123, direction::ON}, {0x2124, 0x2124, direction::L}, + {0x2125, 0x2125, direction::ON}, {0x2126, 0x2126, direction::L}, + {0x2127, 0x2127, direction::ON}, {0x2128, 0x2128, direction::L}, + {0x2129, 0x2129, direction::ON}, {0x212a, 0x212d, direction::L}, + {0x212e, 0x212e, direction::ET}, {0x212f, 0x2139, direction::L}, + {0x213a, 0x213b, direction::ON}, {0x213c, 0x213f, direction::L}, + {0x2140, 0x2144, direction::ON}, {0x2145, 0x2149, direction::L}, + {0x214a, 0x214d, direction::ON}, {0x214e, 0x214f, direction::L}, + {0x2150, 0x215f, direction::ON}, {0x2160, 0x2188, direction::L}, + {0x2189, 0x218b, direction::ON}, {0x2190, 0x2211, direction::ON}, + {0x2212, 0x2212, direction::ES}, {0x2213, 0x2213, direction::ET}, + {0x2214, 0x2335, direction::ON}, {0x2336, 0x237a, direction::L}, + {0x237b, 0x2394, direction::ON}, {0x2395, 0x2395, direction::L}, + {0x2396, 0x2426, direction::ON}, {0x2440, 0x244a, direction::ON}, + {0x2460, 0x2487, direction::ON}, {0x2488, 0x249b, direction::EN}, + {0x249c, 0x24e9, direction::L}, {0x24ea, 0x26ab, direction::ON}, + {0x26ac, 0x26ac, direction::L}, {0x26ad, 0x27ff, direction::ON}, + {0x2800, 0x28ff, direction::L}, {0x2900, 0x2b73, direction::ON}, + {0x2b76, 0x2b95, direction::ON}, {0x2b97, 0x2bff, direction::ON}, + {0x2c00, 0x2c2e, direction::L}, {0x2c30, 0x2c5e, direction::L}, + {0x2c60, 0x2ce4, direction::L}, {0x2ce5, 0x2cea, direction::ON}, + {0x2ceb, 0x2cee, direction::L}, {0x2cef, 0x2cf1, direction::NSM}, + {0x2cf2, 0x2cf3, direction::L}, {0x2cf9, 0x2cff, direction::ON}, + {0x2d00, 0x2d25, direction::L}, {0x2d27, 0x2d27, direction::L}, + {0x2d2d, 0x2d2d, direction::L}, {0x2d30, 0x2d67, direction::L}, + {0x2d6f, 0x2d70, direction::L}, {0x2d7f, 0x2d7f, direction::NSM}, + {0x2d80, 0x2d96, direction::L}, {0x2da0, 0x2da6, direction::L}, + {0x2da8, 0x2dae, direction::L}, {0x2db0, 0x2db6, direction::L}, + {0x2db8, 0x2dbe, direction::L}, {0x2dc0, 0x2dc6, direction::L}, + {0x2dc8, 0x2dce, direction::L}, {0x2dd0, 0x2dd6, direction::L}, + {0x2dd8, 0x2dde, direction::L}, {0x2de0, 0x2dff, direction::NSM}, + {0x2e00, 0x2e52, direction::ON}, {0x2e80, 0x2e99, direction::ON}, + {0x2e9b, 0x2ef3, direction::ON}, {0x2f00, 0x2fd5, direction::ON}, + {0x2ff0, 0x2ffb, direction::ON}, {0x3000, 0x3000, direction::WS}, + {0x3001, 0x3004, direction::ON}, {0x3005, 0x3007, direction::L}, + {0x3008, 0x3020, direction::ON}, {0x3021, 0x3029, direction::L}, + {0x302a, 0x302d, direction::NSM}, {0x302e, 0x302f, direction::L}, + {0x3030, 0x3030, direction::ON}, {0x3031, 0x3035, direction::L}, + {0x3036, 0x3037, direction::ON}, {0x3038, 0x303c, direction::L}, + {0x303d, 0x303f, direction::ON}, {0x3041, 0x3096, direction::L}, + {0x3099, 0x309a, direction::NSM}, {0x309b, 0x309c, direction::ON}, + {0x309d, 0x309f, direction::L}, {0x30a0, 0x30a0, direction::ON}, + {0x30a1, 0x30fa, direction::L}, {0x30fb, 0x30fb, direction::ON}, + {0x30fc, 0x30ff, direction::L}, {0x3105, 0x312f, direction::L}, + {0x3131, 0x318e, direction::L}, {0x3190, 0x31bf, direction::L}, + {0x31c0, 0x31e3, direction::ON}, {0x31f0, 0x321c, direction::L}, + {0x321d, 0x321e, direction::ON}, {0x3220, 0x324f, direction::L}, + {0x3250, 0x325f, direction::ON}, {0x3260, 0x327b, direction::L}, + {0x327c, 0x327e, direction::ON}, {0x327f, 0x32b0, direction::L}, + {0x32b1, 0x32bf, direction::ON}, {0x32c0, 0x32cb, direction::L}, + {0x32cc, 0x32cf, direction::ON}, {0x32d0, 0x3376, direction::L}, + {0x3377, 0x337a, direction::ON}, {0x337b, 0x33dd, direction::L}, + {0x33de, 0x33df, direction::ON}, {0x33e0, 0x33fe, direction::L}, + {0x33ff, 0x33ff, direction::ON}, {0x3400, 0x4dbf, direction::L}, + {0x4dc0, 0x4dff, direction::ON}, {0x4e00, 0x9ffc, direction::L}, + {0xa000, 0xa48c, direction::L}, {0xa490, 0xa4c6, direction::ON}, + {0xa4d0, 0xa60c, direction::L}, {0xa60d, 0xa60f, direction::ON}, + {0xa610, 0xa62b, direction::L}, {0xa640, 0xa66e, direction::L}, + {0xa66f, 0xa672, direction::NSM}, {0xa673, 0xa673, direction::ON}, + {0xa674, 0xa67d, direction::NSM}, {0xa67e, 0xa67f, direction::ON}, + {0xa680, 0xa69d, direction::L}, {0xa69e, 0xa69f, direction::NSM}, + {0xa6a0, 0xa6ef, direction::L}, {0xa6f0, 0xa6f1, direction::NSM}, + {0xa6f2, 0xa6f7, direction::L}, {0xa700, 0xa721, direction::ON}, + {0xa722, 0xa787, direction::L}, {0xa788, 0xa788, direction::ON}, + {0xa789, 0xa7bf, direction::L}, {0xa7c2, 0xa7ca, direction::L}, + {0xa7f5, 0xa801, direction::L}, {0xa802, 0xa802, direction::NSM}, + {0xa803, 0xa805, direction::L}, {0xa806, 0xa806, direction::NSM}, + {0xa807, 0xa80a, direction::L}, {0xa80b, 0xa80b, direction::NSM}, + {0xa80c, 0xa824, direction::L}, {0xa825, 0xa826, direction::NSM}, + {0xa827, 0xa827, direction::L}, {0xa828, 0xa82b, direction::ON}, + {0xa82c, 0xa82c, direction::NSM}, {0xa830, 0xa837, direction::L}, + {0xa838, 0xa839, direction::ET}, {0xa840, 0xa873, direction::L}, + {0xa874, 0xa877, direction::ON}, {0xa880, 0xa8c3, direction::L}, + {0xa8c4, 0xa8c5, direction::NSM}, {0xa8ce, 0xa8d9, direction::L}, + {0xa8e0, 0xa8f1, direction::NSM}, {0xa8f2, 0xa8fe, direction::L}, + {0xa8ff, 0xa8ff, direction::NSM}, {0xa900, 0xa925, direction::L}, + {0xa926, 0xa92d, direction::NSM}, {0xa92e, 0xa946, direction::L}, + {0xa947, 0xa951, direction::NSM}, {0xa952, 0xa953, direction::L}, + {0xa95f, 0xa97c, direction::L}, {0xa980, 0xa982, direction::NSM}, + {0xa983, 0xa9b2, direction::L}, {0xa9b3, 0xa9b3, direction::NSM}, + {0xa9b4, 0xa9b5, direction::L}, {0xa9b6, 0xa9b9, direction::NSM}, + {0xa9ba, 0xa9bb, direction::L}, {0xa9bc, 0xa9bd, direction::NSM}, + {0xa9be, 0xa9cd, direction::L}, {0xa9cf, 0xa9d9, direction::L}, + {0xa9de, 0xa9e4, direction::L}, {0xa9e5, 0xa9e5, direction::NSM}, + {0xa9e6, 0xa9fe, direction::L}, {0xaa00, 0xaa28, direction::L}, + {0xaa29, 0xaa2e, direction::NSM}, {0xaa2f, 0xaa30, direction::L}, + {0xaa31, 0xaa32, direction::NSM}, {0xaa33, 0xaa34, direction::L}, + {0xaa35, 0xaa36, direction::NSM}, {0xaa40, 0xaa42, direction::L}, + {0xaa43, 0xaa43, direction::NSM}, {0xaa44, 0xaa4b, direction::L}, + {0xaa4c, 0xaa4c, direction::NSM}, {0xaa4d, 0xaa4d, direction::L}, + {0xaa50, 0xaa59, direction::L}, {0xaa5c, 0xaa7b, direction::L}, + {0xaa7c, 0xaa7c, direction::NSM}, {0xaa7d, 0xaaaf, direction::L}, + {0xaab0, 0xaab0, direction::NSM}, {0xaab1, 0xaab1, direction::L}, + {0xaab2, 0xaab4, direction::NSM}, {0xaab5, 0xaab6, direction::L}, + {0xaab7, 0xaab8, direction::NSM}, {0xaab9, 0xaabd, direction::L}, + {0xaabe, 0xaabf, direction::NSM}, {0xaac0, 0xaac0, direction::L}, + {0xaac1, 0xaac1, direction::NSM}, {0xaac2, 0xaac2, direction::L}, + {0xaadb, 0xaaeb, direction::L}, {0xaaec, 0xaaed, direction::NSM}, + {0xaaee, 0xaaf5, direction::L}, {0xaaf6, 0xaaf6, direction::NSM}, + {0xab01, 0xab06, direction::L}, {0xab09, 0xab0e, direction::L}, + {0xab11, 0xab16, direction::L}, {0xab20, 0xab26, direction::L}, + {0xab28, 0xab2e, direction::L}, {0xab30, 0xab69, direction::L}, + {0xab6a, 0xab6b, direction::ON}, {0xab70, 0xabe4, direction::L}, + {0xabe5, 0xabe5, direction::NSM}, {0xabe6, 0xabe7, direction::L}, + {0xabe8, 0xabe8, direction::NSM}, {0xabe9, 0xabec, direction::L}, + {0xabed, 0xabed, direction::NSM}, {0xabf0, 0xabf9, direction::L}, + {0xac00, 0xd7a3, direction::L}, {0xd7b0, 0xd7c6, direction::L}, + {0xd7cb, 0xd7fb, direction::L}, {0xd800, 0xfa6d, direction::L}, + {0xfa70, 0xfad9, direction::L}, {0xfb00, 0xfb06, direction::L}, + {0xfb13, 0xfb17, direction::L}, {0xfb1d, 0xfb1d, direction::R}, + {0xfb1e, 0xfb1e, direction::NSM}, {0xfb1f, 0xfb28, direction::R}, + {0xfb29, 0xfb29, direction::ES}, {0xfb2a, 0xfb36, direction::R}, + {0xfb38, 0xfb3c, direction::R}, {0xfb3e, 0xfb3e, direction::R}, + {0xfb40, 0xfb41, direction::R}, {0xfb43, 0xfb44, direction::R}, + {0xfb46, 0xfb4f, direction::R}, {0xfb50, 0xfbc1, direction::AL}, + {0xfbd3, 0xfd3d, direction::AL}, {0xfd3e, 0xfd3f, direction::ON}, + {0xfd50, 0xfd8f, direction::AL}, {0xfd92, 0xfdc7, direction::AL}, + {0xfdf0, 0xfdfc, direction::AL}, {0xfdfd, 0xfdfd, direction::ON}, + {0xfe00, 0xfe0f, direction::NSM}, {0xfe10, 0xfe19, direction::ON}, + {0xfe20, 0xfe2f, direction::NSM}, {0xfe30, 0xfe4f, direction::ON}, + {0xfe50, 0xfe50, direction::CS}, {0xfe51, 0xfe51, direction::ON}, + {0xfe52, 0xfe52, direction::CS}, {0xfe54, 0xfe54, direction::ON}, + {0xfe55, 0xfe55, direction::CS}, {0xfe56, 0xfe5e, direction::ON}, + {0xfe5f, 0xfe5f, direction::ET}, {0xfe60, 0xfe61, direction::ON}, + {0xfe62, 0xfe63, direction::ES}, {0xfe64, 0xfe66, direction::ON}, + {0xfe68, 0xfe68, direction::ON}, {0xfe69, 0xfe6a, direction::ET}, + {0xfe6b, 0xfe6b, direction::ON}, {0xfe70, 0xfe74, direction::AL}, + {0xfe76, 0xfefc, direction::AL}, {0xfeff, 0xfeff, direction::BN}, + {0xff01, 0xff02, direction::ON}, {0xff03, 0xff05, direction::ET}, + {0xff06, 0xff0a, direction::ON}, {0xff0b, 0xff0b, direction::ES}, + {0xff0c, 0xff0c, direction::CS}, {0xff0d, 0xff0d, direction::ES}, + {0xff0e, 0xff0f, direction::CS}, {0xff10, 0xff19, direction::EN}, + {0xff1a, 0xff1a, direction::CS}, {0xff1b, 0xff20, direction::ON}, + {0xff21, 0xff3a, direction::L}, {0xff3b, 0xff40, direction::ON}, + {0xff41, 0xff5a, direction::L}, {0xff5b, 0xff65, direction::ON}, + {0xff66, 0xffbe, direction::L}, {0xffc2, 0xffc7, direction::L}, + {0xffca, 0xffcf, direction::L}, {0xffd2, 0xffd7, direction::L}, + {0xffda, 0xffdc, direction::L}, {0xffe0, 0xffe1, direction::ET}, + {0xffe2, 0xffe4, direction::ON}, {0xffe5, 0xffe6, direction::ET}, + {0xffe8, 0xffee, direction::ON}, {0xfff9, 0xfffd, direction::ON}, + {0x10000, 0x1000b, direction::L}, {0x1000d, 0x10026, direction::L}, + {0x10028, 0x1003a, direction::L}, {0x1003c, 0x1003d, direction::L}, + {0x1003f, 0x1004d, direction::L}, {0x10050, 0x1005d, direction::L}, + {0x10080, 0x100fa, direction::L}, {0x10100, 0x10100, direction::L}, + {0x10101, 0x10101, direction::ON}, {0x10102, 0x10102, direction::L}, + {0x10107, 0x10133, direction::L}, {0x10137, 0x1013f, direction::L}, + {0x10140, 0x1018c, direction::ON}, {0x1018d, 0x1018e, direction::L}, + {0x10190, 0x1019c, direction::ON}, {0x101a0, 0x101a0, direction::ON}, + {0x101d0, 0x101fc, direction::L}, {0x101fd, 0x101fd, direction::NSM}, + {0x10280, 0x1029c, direction::L}, {0x102a0, 0x102d0, direction::L}, + {0x102e0, 0x102e0, direction::NSM}, {0x102e1, 0x102fb, direction::EN}, + {0x10300, 0x10323, direction::L}, {0x1032d, 0x1034a, direction::L}, + {0x10350, 0x10375, direction::L}, {0x10376, 0x1037a, direction::NSM}, + {0x10380, 0x1039d, direction::L}, {0x1039f, 0x103c3, direction::L}, + {0x103c8, 0x103d5, direction::L}, {0x10400, 0x1049d, direction::L}, + {0x104a0, 0x104a9, direction::L}, {0x104b0, 0x104d3, direction::L}, + {0x104d8, 0x104fb, direction::L}, {0x10500, 0x10527, direction::L}, + {0x10530, 0x10563, direction::L}, {0x1056f, 0x1056f, direction::L}, + {0x10600, 0x10736, direction::L}, {0x10740, 0x10755, direction::L}, + {0x10760, 0x10767, direction::L}, {0x10800, 0x10805, direction::R}, + {0x10808, 0x10808, direction::R}, {0x1080a, 0x10835, direction::R}, + {0x10837, 0x10838, direction::R}, {0x1083c, 0x1083c, direction::R}, + {0x1083f, 0x10855, direction::R}, {0x10857, 0x1089e, direction::R}, + {0x108a7, 0x108af, direction::R}, {0x108e0, 0x108f2, direction::R}, + {0x108f4, 0x108f5, direction::R}, {0x108fb, 0x1091b, direction::R}, + {0x1091f, 0x1091f, direction::ON}, {0x10920, 0x10939, direction::R}, + {0x1093f, 0x1093f, direction::R}, {0x10980, 0x109b7, direction::R}, + {0x109bc, 0x109cf, direction::R}, {0x109d2, 0x10a00, direction::R}, + {0x10a01, 0x10a03, direction::NSM}, {0x10a05, 0x10a06, direction::NSM}, + {0x10a0c, 0x10a0f, direction::NSM}, {0x10a10, 0x10a13, direction::R}, + {0x10a15, 0x10a17, direction::R}, {0x10a19, 0x10a35, direction::R}, + {0x10a38, 0x10a3a, direction::NSM}, {0x10a3f, 0x10a3f, direction::NSM}, + {0x10a40, 0x10a48, direction::R}, {0x10a50, 0x10a58, direction::R}, + {0x10a60, 0x10a9f, direction::R}, {0x10ac0, 0x10ae4, direction::R}, + {0x10ae5, 0x10ae6, direction::NSM}, {0x10aeb, 0x10af6, direction::R}, + {0x10b00, 0x10b35, direction::R}, {0x10b39, 0x10b3f, direction::ON}, + {0x10b40, 0x10b55, direction::R}, {0x10b58, 0x10b72, direction::R}, + {0x10b78, 0x10b91, direction::R}, {0x10b99, 0x10b9c, direction::R}, + {0x10ba9, 0x10baf, direction::R}, {0x10c00, 0x10c48, direction::R}, + {0x10c80, 0x10cb2, direction::R}, {0x10cc0, 0x10cf2, direction::R}, + {0x10cfa, 0x10cff, direction::R}, {0x10d00, 0x10d23, direction::AL}, + {0x10d24, 0x10d27, direction::NSM}, {0x10d30, 0x10d39, direction::AN}, + {0x10e60, 0x10e7e, direction::AN}, {0x10e80, 0x10ea9, direction::R}, + {0x10eab, 0x10eac, direction::NSM}, {0x10ead, 0x10ead, direction::R}, + {0x10eb0, 0x10eb1, direction::R}, {0x10f00, 0x10f27, direction::R}, + {0x10f30, 0x10f45, direction::AL}, {0x10f46, 0x10f50, direction::NSM}, + {0x10f51, 0x10f59, direction::AL}, {0x10fb0, 0x10fcb, direction::R}, + {0x10fe0, 0x10ff6, direction::R}, {0x11000, 0x11000, direction::L}, + {0x11001, 0x11001, direction::NSM}, {0x11002, 0x11037, direction::L}, + {0x11038, 0x11046, direction::NSM}, {0x11047, 0x1104d, direction::L}, + {0x11052, 0x11065, direction::ON}, {0x11066, 0x1106f, direction::L}, + {0x1107f, 0x11081, direction::NSM}, {0x11082, 0x110b2, direction::L}, + {0x110b3, 0x110b6, direction::NSM}, {0x110b7, 0x110b8, direction::L}, + {0x110b9, 0x110ba, direction::NSM}, {0x110bb, 0x110c1, direction::L}, + {0x110cd, 0x110cd, direction::L}, {0x110d0, 0x110e8, direction::L}, + {0x110f0, 0x110f9, direction::L}, {0x11100, 0x11102, direction::NSM}, + {0x11103, 0x11126, direction::L}, {0x11127, 0x1112b, direction::NSM}, + {0x1112c, 0x1112c, direction::L}, {0x1112d, 0x11134, direction::NSM}, + {0x11136, 0x11147, direction::L}, {0x11150, 0x11172, direction::L}, + {0x11173, 0x11173, direction::NSM}, {0x11174, 0x11176, direction::L}, + {0x11180, 0x11181, direction::NSM}, {0x11182, 0x111b5, direction::L}, + {0x111b6, 0x111be, direction::NSM}, {0x111bf, 0x111c8, direction::L}, + {0x111c9, 0x111cc, direction::NSM}, {0x111cd, 0x111ce, direction::L}, + {0x111cf, 0x111cf, direction::NSM}, {0x111d0, 0x111df, direction::L}, + {0x111e1, 0x111f4, direction::L}, {0x11200, 0x11211, direction::L}, + {0x11213, 0x1122e, direction::L}, {0x1122f, 0x11231, direction::NSM}, + {0x11232, 0x11233, direction::L}, {0x11234, 0x11234, direction::NSM}, + {0x11235, 0x11235, direction::L}, {0x11236, 0x11237, direction::NSM}, + {0x11238, 0x1123d, direction::L}, {0x1123e, 0x1123e, direction::NSM}, + {0x11280, 0x11286, direction::L}, {0x11288, 0x11288, direction::L}, + {0x1128a, 0x1128d, direction::L}, {0x1128f, 0x1129d, direction::L}, + {0x1129f, 0x112a9, direction::L}, {0x112b0, 0x112de, direction::L}, + {0x112df, 0x112df, direction::NSM}, {0x112e0, 0x112e2, direction::L}, + {0x112e3, 0x112ea, direction::NSM}, {0x112f0, 0x112f9, direction::L}, + {0x11300, 0x11301, direction::NSM}, {0x11302, 0x11303, direction::L}, + {0x11305, 0x1130c, direction::L}, {0x1130f, 0x11310, direction::L}, + {0x11313, 0x11328, direction::L}, {0x1132a, 0x11330, direction::L}, + {0x11332, 0x11333, direction::L}, {0x11335, 0x11339, direction::L}, + {0x1133b, 0x1133c, direction::NSM}, {0x1133d, 0x1133f, direction::L}, + {0x11340, 0x11340, direction::NSM}, {0x11341, 0x11344, direction::L}, + {0x11347, 0x11348, direction::L}, {0x1134b, 0x1134d, direction::L}, + {0x11350, 0x11350, direction::L}, {0x11357, 0x11357, direction::L}, + {0x1135d, 0x11363, direction::L}, {0x11366, 0x1136c, direction::NSM}, + {0x11370, 0x11374, direction::NSM}, {0x11400, 0x11437, direction::L}, + {0x11438, 0x1143f, direction::NSM}, {0x11440, 0x11441, direction::L}, + {0x11442, 0x11444, direction::NSM}, {0x11445, 0x11445, direction::L}, + {0x11446, 0x11446, direction::NSM}, {0x11447, 0x1145b, direction::L}, + {0x1145d, 0x1145d, direction::L}, {0x1145e, 0x1145e, direction::NSM}, + {0x1145f, 0x11461, direction::L}, {0x11480, 0x114b2, direction::L}, + {0x114b3, 0x114b8, direction::NSM}, {0x114b9, 0x114b9, direction::L}, + {0x114ba, 0x114ba, direction::NSM}, {0x114bb, 0x114be, direction::L}, + {0x114bf, 0x114c0, direction::NSM}, {0x114c1, 0x114c1, direction::L}, + {0x114c2, 0x114c3, direction::NSM}, {0x114c4, 0x114c7, direction::L}, + {0x114d0, 0x114d9, direction::L}, {0x11580, 0x115b1, direction::L}, + {0x115b2, 0x115b5, direction::NSM}, {0x115b8, 0x115bb, direction::L}, + {0x115bc, 0x115bd, direction::NSM}, {0x115be, 0x115be, direction::L}, + {0x115bf, 0x115c0, direction::NSM}, {0x115c1, 0x115db, direction::L}, + {0x115dc, 0x115dd, direction::NSM}, {0x11600, 0x11632, direction::L}, + {0x11633, 0x1163a, direction::NSM}, {0x1163b, 0x1163c, direction::L}, + {0x1163d, 0x1163d, direction::NSM}, {0x1163e, 0x1163e, direction::L}, + {0x1163f, 0x11640, direction::NSM}, {0x11641, 0x11644, direction::L}, + {0x11650, 0x11659, direction::L}, {0x11660, 0x1166c, direction::ON}, + {0x11680, 0x116aa, direction::L}, {0x116ab, 0x116ab, direction::NSM}, + {0x116ac, 0x116ac, direction::L}, {0x116ad, 0x116ad, direction::NSM}, + {0x116ae, 0x116af, direction::L}, {0x116b0, 0x116b5, direction::NSM}, + {0x116b6, 0x116b6, direction::L}, {0x116b7, 0x116b7, direction::NSM}, + {0x116b8, 0x116b8, direction::L}, {0x116c0, 0x116c9, direction::L}, + {0x11700, 0x1171a, direction::L}, {0x1171d, 0x1171f, direction::NSM}, + {0x11720, 0x11721, direction::L}, {0x11722, 0x11725, direction::NSM}, + {0x11726, 0x11726, direction::L}, {0x11727, 0x1172b, direction::NSM}, + {0x11730, 0x1173f, direction::L}, {0x11800, 0x1182e, direction::L}, + {0x1182f, 0x11837, direction::NSM}, {0x11838, 0x11838, direction::L}, + {0x11839, 0x1183a, direction::NSM}, {0x1183b, 0x1183b, direction::L}, + {0x118a0, 0x118f2, direction::L}, {0x118ff, 0x11906, direction::L}, + {0x11909, 0x11909, direction::L}, {0x1190c, 0x11913, direction::L}, + {0x11915, 0x11916, direction::L}, {0x11918, 0x11935, direction::L}, + {0x11937, 0x11938, direction::L}, {0x1193b, 0x1193c, direction::NSM}, + {0x1193d, 0x1193d, direction::L}, {0x1193e, 0x1193e, direction::NSM}, + {0x1193f, 0x11942, direction::L}, {0x11943, 0x11943, direction::NSM}, + {0x11944, 0x11946, direction::L}, {0x11950, 0x11959, direction::L}, + {0x119a0, 0x119a7, direction::L}, {0x119aa, 0x119d3, direction::L}, + {0x119d4, 0x119d7, direction::NSM}, {0x119da, 0x119db, direction::NSM}, + {0x119dc, 0x119df, direction::L}, {0x119e0, 0x119e0, direction::NSM}, + {0x119e1, 0x119e4, direction::L}, {0x11a00, 0x11a00, direction::L}, + {0x11a01, 0x11a06, direction::NSM}, {0x11a07, 0x11a08, direction::L}, + {0x11a09, 0x11a0a, direction::NSM}, {0x11a0b, 0x11a32, direction::L}, + {0x11a33, 0x11a38, direction::NSM}, {0x11a39, 0x11a3a, direction::L}, + {0x11a3b, 0x11a3e, direction::NSM}, {0x11a3f, 0x11a46, direction::L}, + {0x11a47, 0x11a47, direction::NSM}, {0x11a50, 0x11a50, direction::L}, + {0x11a51, 0x11a56, direction::NSM}, {0x11a57, 0x11a58, direction::L}, + {0x11a59, 0x11a5b, direction::NSM}, {0x11a5c, 0x11a89, direction::L}, + {0x11a8a, 0x11a96, direction::NSM}, {0x11a97, 0x11a97, direction::L}, + {0x11a98, 0x11a99, direction::NSM}, {0x11a9a, 0x11aa2, direction::L}, + {0x11ac0, 0x11af8, direction::L}, {0x11c00, 0x11c08, direction::L}, + {0x11c0a, 0x11c2f, direction::L}, {0x11c30, 0x11c36, direction::NSM}, + {0x11c38, 0x11c3d, direction::NSM}, {0x11c3e, 0x11c45, direction::L}, + {0x11c50, 0x11c6c, direction::L}, {0x11c70, 0x11c8f, direction::L}, + {0x11c92, 0x11ca7, direction::NSM}, {0x11ca9, 0x11ca9, direction::L}, + {0x11caa, 0x11cb0, direction::NSM}, {0x11cb1, 0x11cb1, direction::L}, + {0x11cb2, 0x11cb3, direction::NSM}, {0x11cb4, 0x11cb4, direction::L}, + {0x11cb5, 0x11cb6, direction::NSM}, {0x11d00, 0x11d06, direction::L}, + {0x11d08, 0x11d09, direction::L}, {0x11d0b, 0x11d30, direction::L}, + {0x11d31, 0x11d36, direction::NSM}, {0x11d3a, 0x11d3a, direction::NSM}, + {0x11d3c, 0x11d3d, direction::NSM}, {0x11d3f, 0x11d45, direction::NSM}, + {0x11d46, 0x11d46, direction::L}, {0x11d47, 0x11d47, direction::NSM}, + {0x11d50, 0x11d59, direction::L}, {0x11d60, 0x11d65, direction::L}, + {0x11d67, 0x11d68, direction::L}, {0x11d6a, 0x11d8e, direction::L}, + {0x11d90, 0x11d91, direction::NSM}, {0x11d93, 0x11d94, direction::L}, + {0x11d95, 0x11d95, direction::NSM}, {0x11d96, 0x11d96, direction::L}, + {0x11d97, 0x11d97, direction::NSM}, {0x11d98, 0x11d98, direction::L}, + {0x11da0, 0x11da9, direction::L}, {0x11ee0, 0x11ef2, direction::L}, + {0x11ef3, 0x11ef4, direction::NSM}, {0x11ef5, 0x11ef8, direction::L}, + {0x11fb0, 0x11fb0, direction::L}, {0x11fc0, 0x11fd4, direction::L}, + {0x11fd5, 0x11fdc, direction::ON}, {0x11fdd, 0x11fe0, direction::ET}, + {0x11fe1, 0x11ff1, direction::ON}, {0x11fff, 0x12399, direction::L}, + {0x12400, 0x1246e, direction::L}, {0x12470, 0x12474, direction::L}, + {0x12480, 0x12543, direction::L}, {0x13000, 0x1342e, direction::L}, + {0x13430, 0x13438, direction::L}, {0x14400, 0x14646, direction::L}, + {0x16800, 0x16a38, direction::L}, {0x16a40, 0x16a5e, direction::L}, + {0x16a60, 0x16a69, direction::L}, {0x16a6e, 0x16a6f, direction::L}, + {0x16ad0, 0x16aed, direction::L}, {0x16af0, 0x16af4, direction::NSM}, + {0x16af5, 0x16af5, direction::L}, {0x16b00, 0x16b2f, direction::L}, + {0x16b30, 0x16b36, direction::NSM}, {0x16b37, 0x16b45, direction::L}, + {0x16b50, 0x16b59, direction::L}, {0x16b5b, 0x16b61, direction::L}, + {0x16b63, 0x16b77, direction::L}, {0x16b7d, 0x16b8f, direction::L}, + {0x16e40, 0x16e9a, direction::L}, {0x16f00, 0x16f4a, direction::L}, + {0x16f4f, 0x16f4f, direction::NSM}, {0x16f50, 0x16f87, direction::L}, + {0x16f8f, 0x16f92, direction::NSM}, {0x16f93, 0x16f9f, direction::L}, + {0x16fe0, 0x16fe1, direction::L}, {0x16fe2, 0x16fe2, direction::ON}, + {0x16fe3, 0x16fe3, direction::L}, {0x16fe4, 0x16fe4, direction::NSM}, + {0x16ff0, 0x16ff1, direction::L}, {0x17000, 0x187f7, direction::L}, + {0x18800, 0x18cd5, direction::L}, {0x18d00, 0x18d08, direction::L}, + {0x1b000, 0x1b11e, direction::L}, {0x1b150, 0x1b152, direction::L}, + {0x1b164, 0x1b167, direction::L}, {0x1b170, 0x1b2fb, direction::L}, + {0x1bc00, 0x1bc6a, direction::L}, {0x1bc70, 0x1bc7c, direction::L}, + {0x1bc80, 0x1bc88, direction::L}, {0x1bc90, 0x1bc99, direction::L}, + {0x1bc9c, 0x1bc9c, direction::L}, {0x1bc9d, 0x1bc9e, direction::NSM}, + {0x1bc9f, 0x1bc9f, direction::L}, {0x1bca0, 0x1bca3, direction::BN}, + {0x1d000, 0x1d0f5, direction::L}, {0x1d100, 0x1d126, direction::L}, + {0x1d129, 0x1d166, direction::L}, {0x1d167, 0x1d169, direction::NSM}, + {0x1d16a, 0x1d172, direction::L}, {0x1d173, 0x1d17a, direction::BN}, + {0x1d17b, 0x1d182, direction::NSM}, {0x1d183, 0x1d184, direction::L}, + {0x1d185, 0x1d18b, direction::NSM}, {0x1d18c, 0x1d1a9, direction::L}, + {0x1d1aa, 0x1d1ad, direction::NSM}, {0x1d1ae, 0x1d1e8, direction::L}, + {0x1d200, 0x1d241, direction::ON}, {0x1d242, 0x1d244, direction::NSM}, + {0x1d245, 0x1d245, direction::ON}, {0x1d2e0, 0x1d2f3, direction::L}, + {0x1d300, 0x1d356, direction::ON}, {0x1d360, 0x1d378, direction::L}, + {0x1d400, 0x1d454, direction::L}, {0x1d456, 0x1d49c, direction::L}, + {0x1d49e, 0x1d49f, direction::L}, {0x1d4a2, 0x1d4a2, direction::L}, + {0x1d4a5, 0x1d4a6, direction::L}, {0x1d4a9, 0x1d4ac, direction::L}, + {0x1d4ae, 0x1d4b9, direction::L}, {0x1d4bb, 0x1d4bb, direction::L}, + {0x1d4bd, 0x1d4c3, direction::L}, {0x1d4c5, 0x1d505, direction::L}, + {0x1d507, 0x1d50a, direction::L}, {0x1d50d, 0x1d514, direction::L}, + {0x1d516, 0x1d51c, direction::L}, {0x1d51e, 0x1d539, direction::L}, + {0x1d53b, 0x1d53e, direction::L}, {0x1d540, 0x1d544, direction::L}, + {0x1d546, 0x1d546, direction::L}, {0x1d54a, 0x1d550, direction::L}, + {0x1d552, 0x1d6a5, direction::L}, {0x1d6a8, 0x1d6da, direction::L}, + {0x1d6db, 0x1d6db, direction::ON}, {0x1d6dc, 0x1d714, direction::L}, + {0x1d715, 0x1d715, direction::ON}, {0x1d716, 0x1d74e, direction::L}, + {0x1d74f, 0x1d74f, direction::ON}, {0x1d750, 0x1d788, direction::L}, + {0x1d789, 0x1d789, direction::ON}, {0x1d78a, 0x1d7c2, direction::L}, + {0x1d7c3, 0x1d7c3, direction::ON}, {0x1d7c4, 0x1d7cb, direction::L}, + {0x1d7ce, 0x1d7ff, direction::EN}, {0x1d800, 0x1d9ff, direction::L}, + {0x1da00, 0x1da36, direction::NSM}, {0x1da37, 0x1da3a, direction::L}, + {0x1da3b, 0x1da6c, direction::NSM}, {0x1da6d, 0x1da74, direction::L}, + {0x1da75, 0x1da75, direction::NSM}, {0x1da76, 0x1da83, direction::L}, + {0x1da84, 0x1da84, direction::NSM}, {0x1da85, 0x1da8b, direction::L}, + {0x1da9b, 0x1da9f, direction::NSM}, {0x1daa1, 0x1daaf, direction::NSM}, + {0x1e000, 0x1e006, direction::NSM}, {0x1e008, 0x1e018, direction::NSM}, + {0x1e01b, 0x1e021, direction::NSM}, {0x1e023, 0x1e024, direction::NSM}, + {0x1e026, 0x1e02a, direction::NSM}, {0x1e100, 0x1e12c, direction::L}, + {0x1e130, 0x1e136, direction::NSM}, {0x1e137, 0x1e13d, direction::L}, + {0x1e140, 0x1e149, direction::L}, {0x1e14e, 0x1e14f, direction::L}, + {0x1e2c0, 0x1e2eb, direction::L}, {0x1e2ec, 0x1e2ef, direction::NSM}, + {0x1e2f0, 0x1e2f9, direction::L}, {0x1e2ff, 0x1e2ff, direction::ET}, + {0x1e800, 0x1e8c4, direction::R}, {0x1e8c7, 0x1e8cf, direction::R}, + {0x1e8d0, 0x1e8d6, direction::NSM}, {0x1e900, 0x1e943, direction::R}, + {0x1e944, 0x1e94a, direction::NSM}, {0x1e94b, 0x1e94b, direction::R}, + {0x1e950, 0x1e959, direction::R}, {0x1e95e, 0x1e95f, direction::R}, + {0x1ec71, 0x1ecb4, direction::AL}, {0x1ed01, 0x1ed3d, direction::AL}, + {0x1ee00, 0x1ee03, direction::AL}, {0x1ee05, 0x1ee1f, direction::AL}, + {0x1ee21, 0x1ee22, direction::AL}, {0x1ee24, 0x1ee24, direction::AL}, + {0x1ee27, 0x1ee27, direction::AL}, {0x1ee29, 0x1ee32, direction::AL}, + {0x1ee34, 0x1ee37, direction::AL}, {0x1ee39, 0x1ee39, direction::AL}, + {0x1ee3b, 0x1ee3b, direction::AL}, {0x1ee42, 0x1ee42, direction::AL}, + {0x1ee47, 0x1ee47, direction::AL}, {0x1ee49, 0x1ee49, direction::AL}, + {0x1ee4b, 0x1ee4b, direction::AL}, {0x1ee4d, 0x1ee4f, direction::AL}, + {0x1ee51, 0x1ee52, direction::AL}, {0x1ee54, 0x1ee54, direction::AL}, + {0x1ee57, 0x1ee57, direction::AL}, {0x1ee59, 0x1ee59, direction::AL}, + {0x1ee5b, 0x1ee5b, direction::AL}, {0x1ee5d, 0x1ee5d, direction::AL}, + {0x1ee5f, 0x1ee5f, direction::AL}, {0x1ee61, 0x1ee62, direction::AL}, + {0x1ee64, 0x1ee64, direction::AL}, {0x1ee67, 0x1ee6a, direction::AL}, + {0x1ee6c, 0x1ee72, direction::AL}, {0x1ee74, 0x1ee77, direction::AL}, + {0x1ee79, 0x1ee7c, direction::AL}, {0x1ee7e, 0x1ee7e, direction::AL}, + {0x1ee80, 0x1ee89, direction::AL}, {0x1ee8b, 0x1ee9b, direction::AL}, + {0x1eea1, 0x1eea3, direction::AL}, {0x1eea5, 0x1eea9, direction::AL}, + {0x1eeab, 0x1eebb, direction::AL}, {0x1eef0, 0x1eef1, direction::ON}, + {0x1f000, 0x1f02b, direction::ON}, {0x1f030, 0x1f093, direction::ON}, + {0x1f0a0, 0x1f0ae, direction::ON}, {0x1f0b1, 0x1f0bf, direction::ON}, + {0x1f0c1, 0x1f0cf, direction::ON}, {0x1f0d1, 0x1f0f5, direction::ON}, + {0x1f100, 0x1f10a, direction::EN}, {0x1f10b, 0x1f10f, direction::ON}, + {0x1f110, 0x1f12e, direction::L}, {0x1f12f, 0x1f12f, direction::ON}, + {0x1f130, 0x1f169, direction::L}, {0x1f16a, 0x1f16f, direction::ON}, + {0x1f170, 0x1f1ac, direction::L}, {0x1f1ad, 0x1f1ad, direction::ON}, + {0x1f1e6, 0x1f202, direction::L}, {0x1f210, 0x1f23b, direction::L}, + {0x1f240, 0x1f248, direction::L}, {0x1f250, 0x1f251, direction::L}, + {0x1f260, 0x1f265, direction::ON}, {0x1f300, 0x1f6d7, direction::ON}, + {0x1f6e0, 0x1f6ec, direction::ON}, {0x1f6f0, 0x1f6fc, direction::ON}, + {0x1f700, 0x1f773, direction::ON}, {0x1f780, 0x1f7d8, direction::ON}, + {0x1f7e0, 0x1f7eb, direction::ON}, {0x1f800, 0x1f80b, direction::ON}, + {0x1f810, 0x1f847, direction::ON}, {0x1f850, 0x1f859, direction::ON}, + {0x1f860, 0x1f887, direction::ON}, {0x1f890, 0x1f8ad, direction::ON}, + {0x1f8b0, 0x1f8b1, direction::ON}, {0x1f900, 0x1f978, direction::ON}, + {0x1f97a, 0x1f9cb, direction::ON}, {0x1f9cd, 0x1fa53, direction::ON}, + {0x1fa60, 0x1fa6d, direction::ON}, {0x1fa70, 0x1fa74, direction::ON}, + {0x1fa78, 0x1fa7a, direction::ON}, {0x1fa80, 0x1fa86, direction::ON}, + {0x1fa90, 0x1faa8, direction::ON}, {0x1fab0, 0x1fab6, direction::ON}, + {0x1fac0, 0x1fac2, direction::ON}, {0x1fad0, 0x1fad6, direction::ON}, + {0x1fb00, 0x1fb92, direction::ON}, {0x1fb94, 0x1fbca, direction::ON}, + {0x1fbf0, 0x1fbf9, direction::EN}, {0x20000, 0x2a6dd, direction::L}, + {0x2a700, 0x2b734, direction::L}, {0x2b740, 0x2b81d, direction::L}, + {0x2b820, 0x2cea1, direction::L}, {0x2ceb0, 0x2ebe0, direction::L}, + {0x2f800, 0x2fa1d, direction::L}, {0x30000, 0x3134a, direction::L}, + {0xe0001, 0xe0001, direction::BN}, {0xe0020, 0xe007f, direction::BN}, + {0xe0100, 0xe01ef, direction::NSM}, {0xf0000, 0xffffd, direction::L}, + {0x100000, 0x10fffd, direction::L}}; + +// CheckJoiners and CheckBidi are true for URL specification. + +inline static direction find_direction(uint32_t code_point) noexcept { + auto it = std::lower_bound( + std::begin(dir_table), std::end(dir_table), code_point, + [](const directions& d, uint32_t c) { return d.final_code < c; }); + + // next check is almost surely in vain, but we use it for safety. + if (it == std::end(dir_table)) { + return direction::NONE; + } + // We have that d.final_code >= c. + if (code_point >= it->start_code) { + return it->direct; + } + return direction::NONE; +} + +inline static size_t find_last_not_of_nsm( + const std::u32string_view label) noexcept { + for (int i = label.size() - 1; i >= 0; i--) + if (find_direction(label[i]) != direction::NSM) return i; + + return std::u32string_view::npos; +} + +// An RTL label is a label that contains at least one character of type R, AL, +// or AN. https://www.rfc-editor.org/rfc/rfc5893#section-2 +inline static bool is_rtl_label(const std::u32string_view label) noexcept { + const size_t mask = + (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN); + + size_t directions = 0; + for (size_t i = 0; i < label.size(); i++) { + directions |= 1u << find_direction(label[i]); + } + return (directions & mask) != 0; +} + +bool is_label_valid(const std::u32string_view label) { + if (label.empty()) { + return true; + } + + /////////////// + // We have a normalization step which ensures that we are in NFC. + // If we receive punycode, we normalize and check that the normalized + // version matches the original. + // -------------------------------------- + // The label must be in Unicode Normalization Form NFC. + + // Current URL standard indicatest that CheckHyphens is set to false. + // --------------------------------------- + // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character + // in both the third and fourth positions. If CheckHyphens, the label must + // neither begin nor end with a U+002D HYPHEN-MINUS character. + + // This is not necessary because we segment the + // labels by '.'. + // --------------------------------------- + // The label must not contain a U+002E ( . ) FULL STOP. + // if (label.find('.') != std::string_view::npos) return false; + + // The label must not begin with a combining mark, that is: + // General_Category=Mark. + constexpr static uint32_t combining[] = { + 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x307, + 0x308, 0x309, 0x30a, 0x30b, 0x30c, 0x30d, 0x30e, 0x30f, + 0x310, 0x311, 0x312, 0x313, 0x314, 0x315, 0x316, 0x317, + 0x318, 0x319, 0x31a, 0x31b, 0x31c, 0x31d, 0x31e, 0x31f, + 0x320, 0x321, 0x322, 0x323, 0x324, 0x325, 0x326, 0x327, + 0x328, 0x329, 0x32a, 0x32b, 0x32c, 0x32d, 0x32e, 0x32f, + 0x330, 0x331, 0x332, 0x333, 0x334, 0x335, 0x336, 0x337, + 0x338, 0x339, 0x33a, 0x33b, 0x33c, 0x33d, 0x33e, 0x33f, + 0x340, 0x341, 0x342, 0x343, 0x344, 0x345, 0x346, 0x347, + 0x348, 0x349, 0x34a, 0x34b, 0x34c, 0x34d, 0x34e, 0x34f, + 0x350, 0x351, 0x352, 0x353, 0x354, 0x355, 0x356, 0x357, + 0x358, 0x359, 0x35a, 0x35b, 0x35c, 0x35d, 0x35e, 0x35f, + 0x360, 0x361, 0x362, 0x363, 0x364, 0x365, 0x366, 0x367, + 0x368, 0x369, 0x36a, 0x36b, 0x36c, 0x36d, 0x36e, 0x36f, + 0x483, 0x484, 0x485, 0x486, 0x487, 0x488, 0x489, 0x591, + 0x592, 0x593, 0x594, 0x595, 0x596, 0x597, 0x598, 0x599, + 0x59a, 0x59b, 0x59c, 0x59d, 0x59e, 0x59f, 0x5a0, 0x5a1, + 0x5a2, 0x5a3, 0x5a4, 0x5a5, 0x5a6, 0x5a7, 0x5a8, 0x5a9, + 0x5aa, 0x5ab, 0x5ac, 0x5ad, 0x5ae, 0x5af, 0x5b0, 0x5b1, + 0x5b2, 0x5b3, 0x5b4, 0x5b5, 0x5b6, 0x5b7, 0x5b8, 0x5b9, + 0x5ba, 0x5bb, 0x5bc, 0x5bd, 0x5bf, 0x5c1, 0x5c2, 0x5c4, + 0x5c5, 0x5c7, 0x610, 0x611, 0x612, 0x613, 0x614, 0x615, + 0x616, 0x617, 0x618, 0x619, 0x61a, 0x64b, 0x64c, 0x64d, + 0x64e, 0x64f, 0x650, 0x651, 0x652, 0x653, 0x654, 0x655, + 0x656, 0x657, 0x658, 0x659, 0x65a, 0x65b, 0x65c, 0x65d, + 0x65e, 0x65f, 0x670, 0x6d6, 0x6d7, 0x6d8, 0x6d9, 0x6da, + 0x6db, 0x6dc, 0x6df, 0x6e0, 0x6e1, 0x6e2, 0x6e3, 0x6e4, + 0x6e7, 0x6e8, 0x6ea, 0x6eb, 0x6ec, 0x6ed, 0x711, 0x730, + 0x731, 0x732, 0x733, 0x734, 0x735, 0x736, 0x737, 0x738, + 0x739, 0x73a, 0x73b, 0x73c, 0x73d, 0x73e, 0x73f, 0x740, + 0x741, 0x742, 0x743, 0x744, 0x745, 0x746, 0x747, 0x748, + 0x749, 0x74a, 0x7a6, 0x7a7, 0x7a8, 0x7a9, 0x7aa, 0x7ab, + 0x7ac, 0x7ad, 0x7ae, 0x7af, 0x7b0, 0x7eb, 0x7ec, 0x7ed, + 0x7ee, 0x7ef, 0x7f0, 0x7f1, 0x7f2, 0x7f3, 0x7fd, 0x816, + 0x817, 0x818, 0x819, 0x81b, 0x81c, 0x81d, 0x81e, 0x81f, + 0x820, 0x821, 0x822, 0x823, 0x825, 0x826, 0x827, 0x829, + 0x82a, 0x82b, 0x82c, 0x82d, 0x859, 0x85a, 0x85b, 0x8d3, + 0x8d4, 0x8d5, 0x8d6, 0x8d7, 0x8d8, 0x8d9, 0x8da, 0x8db, + 0x8dc, 0x8dd, 0x8de, 0x8df, 0x8e0, 0x8e1, 0x8e3, 0x8e4, + 0x8e5, 0x8e6, 0x8e7, 0x8e8, 0x8e9, 0x8ea, 0x8eb, 0x8ec, + 0x8ed, 0x8ee, 0x8ef, 0x8f0, 0x8f1, 0x8f2, 0x8f3, 0x8f4, + 0x8f5, 0x8f6, 0x8f7, 0x8f8, 0x8f9, 0x8fa, 0x8fb, 0x8fc, + 0x8fd, 0x8fe, 0x8ff, 0x900, 0x901, 0x902, 0x903, 0x93a, + 0x93b, 0x93c, 0x93e, 0x93f, 0x940, 0x941, 0x942, 0x943, + 0x944, 0x945, 0x946, 0x947, 0x948, 0x949, 0x94a, 0x94b, + 0x94c, 0x94d, 0x94e, 0x94f, 0x951, 0x952, 0x953, 0x954, + 0x955, 0x956, 0x957, 0x962, 0x963, 0x981, 0x982, 0x983, + 0x9bc, 0x9be, 0x9bf, 0x9c0, 0x9c1, 0x9c2, 0x9c3, 0x9c4, + 0x9c7, 0x9c8, 0x9cb, 0x9cc, 0x9cd, 0x9d7, 0x9e2, 0x9e3, + 0x9fe, 0xa01, 0xa02, 0xa03, 0xa3c, 0xa3e, 0xa3f, 0xa40, + 0xa41, 0xa42, 0xa47, 0xa48, 0xa4b, 0xa4c, 0xa4d, 0xa51, + 0xa70, 0xa71, 0xa75, 0xa81, 0xa82, 0xa83, 0xabc, 0xabe, + 0xabf, 0xac0, 0xac1, 0xac2, 0xac3, 0xac4, 0xac5, 0xac7, + 0xac8, 0xac9, 0xacb, 0xacc, 0xacd, 0xae2, 0xae3, 0xafa, + 0xafb, 0xafc, 0xafd, 0xafe, 0xaff, 0xb01, 0xb02, 0xb03, + 0xb3c, 0xb3e, 0xb3f, 0xb40, 0xb41, 0xb42, 0xb43, 0xb44, + 0xb47, 0xb48, 0xb4b, 0xb4c, 0xb4d, 0xb55, 0xb56, 0xb57, + 0xb62, 0xb63, 0xb82, 0xbbe, 0xbbf, 0xbc0, 0xbc1, 0xbc2, + 0xbc6, 0xbc7, 0xbc8, 0xbca, 0xbcb, 0xbcc, 0xbcd, 0xbd7, + 0xc00, 0xc01, 0xc02, 0xc03, 0xc04, 0xc3e, 0xc3f, 0xc40, + 0xc41, 0xc42, 0xc43, 0xc44, 0xc46, 0xc47, 0xc48, 0xc4a, + 0xc4b, 0xc4c, 0xc4d, 0xc55, 0xc56, 0xc62, 0xc63, 0xc81, + 0xc82, 0xc83, 0xcbc, 0xcbe, 0xcbf, 0xcc0, 0xcc1, 0xcc2, + 0xcc3, 0xcc4, 0xcc6, 0xcc7, 0xcc8, 0xcca, 0xccb, 0xccc, + 0xccd, 0xcd5, 0xcd6, 0xce2, 0xce3, 0xd00, 0xd01, 0xd02, + 0xd03, 0xd3b, 0xd3c, 0xd3e, 0xd3f, 0xd40, 0xd41, 0xd42, + 0xd43, 0xd44, 0xd46, 0xd47, 0xd48, 0xd4a, 0xd4b, 0xd4c, + 0xd4d, 0xd57, 0xd62, 0xd63, 0xd81, 0xd82, 0xd83, 0xdca, + 0xdcf, 0xdd0, 0xdd1, 0xdd2, 0xdd3, 0xdd4, 0xdd6, 0xdd8, + 0xdd9, 0xdda, 0xddb, 0xddc, 0xddd, 0xdde, 0xddf, 0xdf2, + 0xdf3, 0xe31, 0xe34, 0xe35, 0xe36, 0xe37, 0xe38, 0xe39, + 0xe3a, 0xe47, 0xe48, 0xe49, 0xe4a, 0xe4b, 0xe4c, 0xe4d, + 0xe4e, 0xeb1, 0xeb4, 0xeb5, 0xeb6, 0xeb7, 0xeb8, 0xeb9, + 0xeba, 0xebb, 0xebc, 0xec8, 0xec9, 0xeca, 0xecb, 0xecc, + 0xecd, 0xf18, 0xf19, 0xf35, 0xf37, 0xf39, 0xf3e, 0xf3f, + 0xf71, 0xf72, 0xf73, 0xf74, 0xf75, 0xf76, 0xf77, 0xf78, + 0xf79, 0xf7a, 0xf7b, 0xf7c, 0xf7d, 0xf7e, 0xf7f, 0xf80, + 0xf81, 0xf82, 0xf83, 0xf84, 0xf86, 0xf87, 0xf8d, 0xf8e, + 0xf8f, 0xf90, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, 0xf96, + 0xf97, 0xf99, 0xf9a, 0xf9b, 0xf9c, 0xf9d, 0xf9e, 0xf9f, + 0xfa0, 0xfa1, 0xfa2, 0xfa3, 0xfa4, 0xfa5, 0xfa6, 0xfa7, + 0xfa8, 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0xfae, 0xfaf, + 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, 0xfb6, 0xfb7, + 0xfb8, 0xfb9, 0xfba, 0xfbb, 0xfbc, 0xfc6, 0x102b, 0x102c, + 0x102d, 0x102e, 0x102f, 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, + 0x1035, 0x1036, 0x1037, 0x1038, 0x1039, 0x103a, 0x103b, 0x103c, + 0x103d, 0x103e, 0x1056, 0x1057, 0x1058, 0x1059, 0x105e, 0x105f, + 0x1060, 0x1062, 0x1063, 0x1064, 0x1067, 0x1068, 0x1069, 0x106a, + 0x106b, 0x106c, 0x106d, 0x1071, 0x1072, 0x1073, 0x1074, 0x1082, + 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 0x1088, 0x1089, 0x108a, + 0x108b, 0x108c, 0x108d, 0x108f, 0x109a, 0x109b, 0x109c, 0x109d, + 0x135d, 0x135e, 0x135f, 0x1712, 0x1713, 0x1714, 0x1732, 0x1733, + 0x1734, 0x1752, 0x1753, 0x1772, 0x1773, 0x17b4, 0x17b5, 0x17b6, + 0x17b7, 0x17b8, 0x17b9, 0x17ba, 0x17bb, 0x17bc, 0x17bd, 0x17be, + 0x17bf, 0x17c0, 0x17c1, 0x17c2, 0x17c3, 0x17c4, 0x17c5, 0x17c6, + 0x17c7, 0x17c8, 0x17c9, 0x17ca, 0x17cb, 0x17cc, 0x17cd, 0x17ce, + 0x17cf, 0x17d0, 0x17d1, 0x17d2, 0x17d3, 0x17dd, 0x180b, 0x180c, + 0x180d, 0x1885, 0x1886, 0x18a9, 0x1920, 0x1921, 0x1922, 0x1923, + 0x1924, 0x1925, 0x1926, 0x1927, 0x1928, 0x1929, 0x192a, 0x192b, + 0x1930, 0x1931, 0x1932, 0x1933, 0x1934, 0x1935, 0x1936, 0x1937, + 0x1938, 0x1939, 0x193a, 0x193b, 0x1a17, 0x1a18, 0x1a19, 0x1a1a, + 0x1a1b, 0x1a55, 0x1a56, 0x1a57, 0x1a58, 0x1a59, 0x1a5a, 0x1a5b, + 0x1a5c, 0x1a5d, 0x1a5e, 0x1a60, 0x1a61, 0x1a62, 0x1a63, 0x1a64, + 0x1a65, 0x1a66, 0x1a67, 0x1a68, 0x1a69, 0x1a6a, 0x1a6b, 0x1a6c, + 0x1a6d, 0x1a6e, 0x1a6f, 0x1a70, 0x1a71, 0x1a72, 0x1a73, 0x1a74, + 0x1a75, 0x1a76, 0x1a77, 0x1a78, 0x1a79, 0x1a7a, 0x1a7b, 0x1a7c, + 0x1a7f, 0x1ab0, 0x1ab1, 0x1ab2, 0x1ab3, 0x1ab4, 0x1ab5, 0x1ab6, + 0x1ab7, 0x1ab8, 0x1ab9, 0x1aba, 0x1abb, 0x1abc, 0x1abd, 0x1abe, + 0x1abf, 0x1ac0, 0x1b00, 0x1b01, 0x1b02, 0x1b03, 0x1b04, 0x1b34, + 0x1b35, 0x1b36, 0x1b37, 0x1b38, 0x1b39, 0x1b3a, 0x1b3b, 0x1b3c, + 0x1b3d, 0x1b3e, 0x1b3f, 0x1b40, 0x1b41, 0x1b42, 0x1b43, 0x1b44, + 0x1b6b, 0x1b6c, 0x1b6d, 0x1b6e, 0x1b6f, 0x1b70, 0x1b71, 0x1b72, + 0x1b73, 0x1b80, 0x1b81, 0x1b82, 0x1ba1, 0x1ba2, 0x1ba3, 0x1ba4, + 0x1ba5, 0x1ba6, 0x1ba7, 0x1ba8, 0x1ba9, 0x1baa, 0x1bab, 0x1bac, + 0x1bad, 0x1be6, 0x1be7, 0x1be8, 0x1be9, 0x1bea, 0x1beb, 0x1bec, + 0x1bed, 0x1bee, 0x1bef, 0x1bf0, 0x1bf1, 0x1bf2, 0x1bf3, 0x1c24, + 0x1c25, 0x1c26, 0x1c27, 0x1c28, 0x1c29, 0x1c2a, 0x1c2b, 0x1c2c, + 0x1c2d, 0x1c2e, 0x1c2f, 0x1c30, 0x1c31, 0x1c32, 0x1c33, 0x1c34, + 0x1c35, 0x1c36, 0x1c37, 0x1cd0, 0x1cd1, 0x1cd2, 0x1cd4, 0x1cd5, + 0x1cd6, 0x1cd7, 0x1cd8, 0x1cd9, 0x1cda, 0x1cdb, 0x1cdc, 0x1cdd, + 0x1cde, 0x1cdf, 0x1ce0, 0x1ce1, 0x1ce2, 0x1ce3, 0x1ce4, 0x1ce5, + 0x1ce6, 0x1ce7, 0x1ce8, 0x1ced, 0x1cf4, 0x1cf7, 0x1cf8, 0x1cf9, + 0x1dc0, 0x1dc1, 0x1dc2, 0x1dc3, 0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7, + 0x1dc8, 0x1dc9, 0x1dca, 0x1dcb, 0x1dcc, 0x1dcd, 0x1dce, 0x1dcf, + 0x1dd0, 0x1dd1, 0x1dd2, 0x1dd3, 0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7, + 0x1dd8, 0x1dd9, 0x1dda, 0x1ddb, 0x1ddc, 0x1ddd, 0x1dde, 0x1ddf, + 0x1de0, 0x1de1, 0x1de2, 0x1de3, 0x1de4, 0x1de5, 0x1de6, 0x1de7, + 0x1de8, 0x1de9, 0x1dea, 0x1deb, 0x1dec, 0x1ded, 0x1dee, 0x1def, + 0x1df0, 0x1df1, 0x1df2, 0x1df3, 0x1df4, 0x1df5, 0x1df6, 0x1df7, + 0x1df8, 0x1df9, 0x1dfb, 0x1dfc, 0x1dfd, 0x1dfe, 0x1dff, 0x20d0, + 0x20d1, 0x20d2, 0x20d3, 0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20d8, + 0x20d9, 0x20da, 0x20db, 0x20dc, 0x20dd, 0x20de, 0x20df, 0x20e0, + 0x20e1, 0x20e2, 0x20e3, 0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x20e8, + 0x20e9, 0x20ea, 0x20eb, 0x20ec, 0x20ed, 0x20ee, 0x20ef, 0x20f0, + 0x2cef, 0x2cf0, 0x2cf1, 0x2d7f, 0x2de0, 0x2de1, 0x2de2, 0x2de3, + 0x2de4, 0x2de5, 0x2de6, 0x2de7, 0x2de8, 0x2de9, 0x2dea, 0x2deb, + 0x2dec, 0x2ded, 0x2dee, 0x2def, 0x2df0, 0x2df1, 0x2df2, 0x2df3, + 0x2df4, 0x2df5, 0x2df6, 0x2df7, 0x2df8, 0x2df9, 0x2dfa, 0x2dfb, + 0x2dfc, 0x2dfd, 0x2dfe, 0x2dff, 0x302a, 0x302b, 0x302c, 0x302d, + 0x302e, 0x302f, 0x3099, 0x309a, 0xa66f, 0xa670, 0xa671, 0xa672, + 0xa674, 0xa675, 0xa676, 0xa677, 0xa678, 0xa679, 0xa67a, 0xa67b, + 0xa67c, 0xa67d, 0xa69e, 0xa69f, 0xa6f0, 0xa6f1, 0xa802, 0xa806, + 0xa80b, 0xa823, 0xa824, 0xa825, 0xa826, 0xa827, 0xa82c, 0xa880, + 0xa881, 0xa8b4, 0xa8b5, 0xa8b6, 0xa8b7, 0xa8b8, 0xa8b9, 0xa8ba, + 0xa8bb, 0xa8bc, 0xa8bd, 0xa8be, 0xa8bf, 0xa8c0, 0xa8c1, 0xa8c2, + 0xa8c3, 0xa8c4, 0xa8c5, 0xa8e0, 0xa8e1, 0xa8e2, 0xa8e3, 0xa8e4, + 0xa8e5, 0xa8e6, 0xa8e7, 0xa8e8, 0xa8e9, 0xa8ea, 0xa8eb, 0xa8ec, + 0xa8ed, 0xa8ee, 0xa8ef, 0xa8f0, 0xa8f1, 0xa8ff, 0xa926, 0xa927, + 0xa928, 0xa929, 0xa92a, 0xa92b, 0xa92c, 0xa92d, 0xa947, 0xa948, + 0xa949, 0xa94a, 0xa94b, 0xa94c, 0xa94d, 0xa94e, 0xa94f, 0xa950, + 0xa951, 0xa952, 0xa953, 0xa980, 0xa981, 0xa982, 0xa983, 0xa9b3, + 0xa9b4, 0xa9b5, 0xa9b6, 0xa9b7, 0xa9b8, 0xa9b9, 0xa9ba, 0xa9bb, + 0xa9bc, 0xa9bd, 0xa9be, 0xa9bf, 0xa9c0, 0xa9e5, 0xaa29, 0xaa2a, + 0xaa2b, 0xaa2c, 0xaa2d, 0xaa2e, 0xaa2f, 0xaa30, 0xaa31, 0xaa32, + 0xaa33, 0xaa34, 0xaa35, 0xaa36, 0xaa43, 0xaa4c, 0xaa4d, 0xaa7b, + 0xaa7c, 0xaa7d, 0xaab0, 0xaab2, 0xaab3, 0xaab4, 0xaab7, 0xaab8, + 0xaabe, 0xaabf, 0xaac1, 0xaaeb, 0xaaec, 0xaaed, 0xaaee, 0xaaef, + 0xaaf5, 0xaaf6, 0xabe3, 0xabe4, 0xabe5, 0xabe6, 0xabe7, 0xabe8, + 0xabe9, 0xabea, 0xabec, 0xabed, 0xfb1e, 0xfe00, 0xfe01, 0xfe02, + 0xfe03, 0xfe04, 0xfe05, 0xfe06, 0xfe07, 0xfe08, 0xfe09, 0xfe0a, + 0xfe0b, 0xfe0c, 0xfe0d, 0xfe0e, 0xfe0f, 0xfe20, 0xfe21, 0xfe22, + 0xfe23, 0xfe24, 0xfe25, 0xfe26, 0xfe27, 0xfe28, 0xfe29, 0xfe2a, + 0xfe2b, 0xfe2c, 0xfe2d, 0xfe2e, 0xfe2f, 0x101fd, 0x102e0, 0x10376, + 0x10377, 0x10378, 0x10379, 0x1037a, 0x10a01, 0x10a02, 0x10a03, 0x10a05, + 0x10a06, 0x10a0c, 0x10a0d, 0x10a0e, 0x10a0f, 0x10a38, 0x10a39, 0x10a3a, + 0x10a3f, 0x10ae5, 0x10ae6, 0x10d24, 0x10d25, 0x10d26, 0x10d27, 0x10eab, + 0x10eac, 0x10f46, 0x10f47, 0x10f48, 0x10f49, 0x10f4a, 0x10f4b, 0x10f4c, + 0x10f4d, 0x10f4e, 0x10f4f, 0x10f50, 0x11000, 0x11001, 0x11002, 0x11038, + 0x11039, 0x1103a, 0x1103b, 0x1103c, 0x1103d, 0x1103e, 0x1103f, 0x11040, + 0x11041, 0x11042, 0x11043, 0x11044, 0x11045, 0x11046, 0x1107f, 0x11080, + 0x11081, 0x11082, 0x110b0, 0x110b1, 0x110b2, 0x110b3, 0x110b4, 0x110b5, + 0x110b6, 0x110b7, 0x110b8, 0x110b9, 0x110ba, 0x11100, 0x11101, 0x11102, + 0x11127, 0x11128, 0x11129, 0x1112a, 0x1112b, 0x1112c, 0x1112d, 0x1112e, + 0x1112f, 0x11130, 0x11131, 0x11132, 0x11133, 0x11134, 0x11145, 0x11146, + 0x11173, 0x11180, 0x11181, 0x11182, 0x111b3, 0x111b4, 0x111b5, 0x111b6, + 0x111b7, 0x111b8, 0x111b9, 0x111ba, 0x111bb, 0x111bc, 0x111bd, 0x111be, + 0x111bf, 0x111c0, 0x111c9, 0x111ca, 0x111cb, 0x111cc, 0x111ce, 0x111cf, + 0x1122c, 0x1122d, 0x1122e, 0x1122f, 0x11230, 0x11231, 0x11232, 0x11233, + 0x11234, 0x11235, 0x11236, 0x11237, 0x1123e, 0x112df, 0x112e0, 0x112e1, + 0x112e2, 0x112e3, 0x112e4, 0x112e5, 0x112e6, 0x112e7, 0x112e8, 0x112e9, + 0x112ea, 0x11300, 0x11301, 0x11302, 0x11303, 0x1133b, 0x1133c, 0x1133e, + 0x1133f, 0x11340, 0x11341, 0x11342, 0x11343, 0x11344, 0x11347, 0x11348, + 0x1134b, 0x1134c, 0x1134d, 0x11357, 0x11362, 0x11363, 0x11366, 0x11367, + 0x11368, 0x11369, 0x1136a, 0x1136b, 0x1136c, 0x11370, 0x11371, 0x11372, + 0x11373, 0x11374, 0x11435, 0x11436, 0x11437, 0x11438, 0x11439, 0x1143a, + 0x1143b, 0x1143c, 0x1143d, 0x1143e, 0x1143f, 0x11440, 0x11441, 0x11442, + 0x11443, 0x11444, 0x11445, 0x11446, 0x1145e, 0x114b0, 0x114b1, 0x114b2, + 0x114b3, 0x114b4, 0x114b5, 0x114b6, 0x114b7, 0x114b8, 0x114b9, 0x114ba, + 0x114bb, 0x114bc, 0x114bd, 0x114be, 0x114bf, 0x114c0, 0x114c1, 0x114c2, + 0x114c3, 0x115af, 0x115b0, 0x115b1, 0x115b2, 0x115b3, 0x115b4, 0x115b5, + 0x115b8, 0x115b9, 0x115ba, 0x115bb, 0x115bc, 0x115bd, 0x115be, 0x115bf, + 0x115c0, 0x115dc, 0x115dd, 0x11630, 0x11631, 0x11632, 0x11633, 0x11634, + 0x11635, 0x11636, 0x11637, 0x11638, 0x11639, 0x1163a, 0x1163b, 0x1163c, + 0x1163d, 0x1163e, 0x1163f, 0x11640, 0x116ab, 0x116ac, 0x116ad, 0x116ae, + 0x116af, 0x116b0, 0x116b1, 0x116b2, 0x116b3, 0x116b4, 0x116b5, 0x116b6, + 0x116b7, 0x1171d, 0x1171e, 0x1171f, 0x11720, 0x11721, 0x11722, 0x11723, + 0x11724, 0x11725, 0x11726, 0x11727, 0x11728, 0x11729, 0x1172a, 0x1172b, + 0x1182c, 0x1182d, 0x1182e, 0x1182f, 0x11830, 0x11831, 0x11832, 0x11833, + 0x11834, 0x11835, 0x11836, 0x11837, 0x11838, 0x11839, 0x1183a, 0x11930, + 0x11931, 0x11932, 0x11933, 0x11934, 0x11935, 0x11937, 0x11938, 0x1193b, + 0x1193c, 0x1193d, 0x1193e, 0x11940, 0x11942, 0x11943, 0x119d1, 0x119d2, + 0x119d3, 0x119d4, 0x119d5, 0x119d6, 0x119d7, 0x119da, 0x119db, 0x119dc, + 0x119dd, 0x119de, 0x119df, 0x119e0, 0x119e4, 0x11a01, 0x11a02, 0x11a03, + 0x11a04, 0x11a05, 0x11a06, 0x11a07, 0x11a08, 0x11a09, 0x11a0a, 0x11a33, + 0x11a34, 0x11a35, 0x11a36, 0x11a37, 0x11a38, 0x11a39, 0x11a3b, 0x11a3c, + 0x11a3d, 0x11a3e, 0x11a47, 0x11a51, 0x11a52, 0x11a53, 0x11a54, 0x11a55, + 0x11a56, 0x11a57, 0x11a58, 0x11a59, 0x11a5a, 0x11a5b, 0x11a8a, 0x11a8b, + 0x11a8c, 0x11a8d, 0x11a8e, 0x11a8f, 0x11a90, 0x11a91, 0x11a92, 0x11a93, + 0x11a94, 0x11a95, 0x11a96, 0x11a97, 0x11a98, 0x11a99, 0x11c2f, 0x11c30, + 0x11c31, 0x11c32, 0x11c33, 0x11c34, 0x11c35, 0x11c36, 0x11c38, 0x11c39, + 0x11c3a, 0x11c3b, 0x11c3c, 0x11c3d, 0x11c3e, 0x11c3f, 0x11c92, 0x11c93, + 0x11c94, 0x11c95, 0x11c96, 0x11c97, 0x11c98, 0x11c99, 0x11c9a, 0x11c9b, + 0x11c9c, 0x11c9d, 0x11c9e, 0x11c9f, 0x11ca0, 0x11ca1, 0x11ca2, 0x11ca3, + 0x11ca4, 0x11ca5, 0x11ca6, 0x11ca7, 0x11ca9, 0x11caa, 0x11cab, 0x11cac, + 0x11cad, 0x11cae, 0x11caf, 0x11cb0, 0x11cb1, 0x11cb2, 0x11cb3, 0x11cb4, + 0x11cb5, 0x11cb6, 0x11d31, 0x11d32, 0x11d33, 0x11d34, 0x11d35, 0x11d36, + 0x11d3a, 0x11d3c, 0x11d3d, 0x11d3f, 0x11d40, 0x11d41, 0x11d42, 0x11d43, + 0x11d44, 0x11d45, 0x11d47, 0x11d8a, 0x11d8b, 0x11d8c, 0x11d8d, 0x11d8e, + 0x11d90, 0x11d91, 0x11d93, 0x11d94, 0x11d95, 0x11d96, 0x11d97, 0x11ef3, + 0x11ef4, 0x11ef5, 0x11ef6, 0x16af0, 0x16af1, 0x16af2, 0x16af3, 0x16af4, + 0x16b30, 0x16b31, 0x16b32, 0x16b33, 0x16b34, 0x16b35, 0x16b36, 0x16f4f, + 0x16f51, 0x16f52, 0x16f53, 0x16f54, 0x16f55, 0x16f56, 0x16f57, 0x16f58, + 0x16f59, 0x16f5a, 0x16f5b, 0x16f5c, 0x16f5d, 0x16f5e, 0x16f5f, 0x16f60, + 0x16f61, 0x16f62, 0x16f63, 0x16f64, 0x16f65, 0x16f66, 0x16f67, 0x16f68, + 0x16f69, 0x16f6a, 0x16f6b, 0x16f6c, 0x16f6d, 0x16f6e, 0x16f6f, 0x16f70, + 0x16f71, 0x16f72, 0x16f73, 0x16f74, 0x16f75, 0x16f76, 0x16f77, 0x16f78, + 0x16f79, 0x16f7a, 0x16f7b, 0x16f7c, 0x16f7d, 0x16f7e, 0x16f7f, 0x16f80, + 0x16f81, 0x16f82, 0x16f83, 0x16f84, 0x16f85, 0x16f86, 0x16f87, 0x16f8f, + 0x16f90, 0x16f91, 0x16f92, 0x16fe4, 0x16ff0, 0x16ff1, 0x1bc9d, 0x1bc9e, + 0x1d165, 0x1d166, 0x1d167, 0x1d168, 0x1d169, 0x1d16d, 0x1d16e, 0x1d16f, + 0x1d170, 0x1d171, 0x1d172, 0x1d17b, 0x1d17c, 0x1d17d, 0x1d17e, 0x1d17f, + 0x1d180, 0x1d181, 0x1d182, 0x1d185, 0x1d186, 0x1d187, 0x1d188, 0x1d189, + 0x1d18a, 0x1d18b, 0x1d1aa, 0x1d1ab, 0x1d1ac, 0x1d1ad, 0x1d242, 0x1d243, + 0x1d244, 0x1da00, 0x1da01, 0x1da02, 0x1da03, 0x1da04, 0x1da05, 0x1da06, + 0x1da07, 0x1da08, 0x1da09, 0x1da0a, 0x1da0b, 0x1da0c, 0x1da0d, 0x1da0e, + 0x1da0f, 0x1da10, 0x1da11, 0x1da12, 0x1da13, 0x1da14, 0x1da15, 0x1da16, + 0x1da17, 0x1da18, 0x1da19, 0x1da1a, 0x1da1b, 0x1da1c, 0x1da1d, 0x1da1e, + 0x1da1f, 0x1da20, 0x1da21, 0x1da22, 0x1da23, 0x1da24, 0x1da25, 0x1da26, + 0x1da27, 0x1da28, 0x1da29, 0x1da2a, 0x1da2b, 0x1da2c, 0x1da2d, 0x1da2e, + 0x1da2f, 0x1da30, 0x1da31, 0x1da32, 0x1da33, 0x1da34, 0x1da35, 0x1da36, + 0x1da3b, 0x1da3c, 0x1da3d, 0x1da3e, 0x1da3f, 0x1da40, 0x1da41, 0x1da42, + 0x1da43, 0x1da44, 0x1da45, 0x1da46, 0x1da47, 0x1da48, 0x1da49, 0x1da4a, + 0x1da4b, 0x1da4c, 0x1da4d, 0x1da4e, 0x1da4f, 0x1da50, 0x1da51, 0x1da52, + 0x1da53, 0x1da54, 0x1da55, 0x1da56, 0x1da57, 0x1da58, 0x1da59, 0x1da5a, + 0x1da5b, 0x1da5c, 0x1da5d, 0x1da5e, 0x1da5f, 0x1da60, 0x1da61, 0x1da62, + 0x1da63, 0x1da64, 0x1da65, 0x1da66, 0x1da67, 0x1da68, 0x1da69, 0x1da6a, + 0x1da6b, 0x1da6c, 0x1da75, 0x1da84, 0x1da9b, 0x1da9c, 0x1da9d, 0x1da9e, + 0x1da9f, 0x1daa1, 0x1daa2, 0x1daa3, 0x1daa4, 0x1daa5, 0x1daa6, 0x1daa7, + 0x1daa8, 0x1daa9, 0x1daaa, 0x1daab, 0x1daac, 0x1daad, 0x1daae, 0x1daaf, + 0x1e000, 0x1e001, 0x1e002, 0x1e003, 0x1e004, 0x1e005, 0x1e006, 0x1e008, + 0x1e009, 0x1e00a, 0x1e00b, 0x1e00c, 0x1e00d, 0x1e00e, 0x1e00f, 0x1e010, + 0x1e011, 0x1e012, 0x1e013, 0x1e014, 0x1e015, 0x1e016, 0x1e017, 0x1e018, + 0x1e01b, 0x1e01c, 0x1e01d, 0x1e01e, 0x1e01f, 0x1e020, 0x1e021, 0x1e023, + 0x1e024, 0x1e026, 0x1e027, 0x1e028, 0x1e029, 0x1e02a, 0x1e130, 0x1e131, + 0x1e132, 0x1e133, 0x1e134, 0x1e135, 0x1e136, 0x1e2ec, 0x1e2ed, 0x1e2ee, + 0x1e2ef, 0x1e8d0, 0x1e8d1, 0x1e8d2, 0x1e8d3, 0x1e8d4, 0x1e8d5, 0x1e8d6, + 0x1e944, 0x1e945, 0x1e946, 0x1e947, 0x1e948, 0x1e949, 0x1e94a, 0xe0100, + 0xe0101, 0xe0102, 0xe0103, 0xe0104, 0xe0105, 0xe0106, 0xe0107, 0xe0108, + 0xe0109, 0xe010a, 0xe010b, 0xe010c, 0xe010d, 0xe010e, 0xe010f, 0xe0110, + 0xe0111, 0xe0112, 0xe0113, 0xe0114, 0xe0115, 0xe0116, 0xe0117, 0xe0118, + 0xe0119, 0xe011a, 0xe011b, 0xe011c, 0xe011d, 0xe011e, 0xe011f, 0xe0120, + 0xe0121, 0xe0122, 0xe0123, 0xe0124, 0xe0125, 0xe0126, 0xe0127, 0xe0128, + 0xe0129, 0xe012a, 0xe012b, 0xe012c, 0xe012d, 0xe012e, 0xe012f, 0xe0130, + 0xe0131, 0xe0132, 0xe0133, 0xe0134, 0xe0135, 0xe0136, 0xe0137, 0xe0138, + 0xe0139, 0xe013a, 0xe013b, 0xe013c, 0xe013d, 0xe013e, 0xe013f, 0xe0140, + 0xe0141, 0xe0142, 0xe0143, 0xe0144, 0xe0145, 0xe0146, 0xe0147, 0xe0148, + 0xe0149, 0xe014a, 0xe014b, 0xe014c, 0xe014d, 0xe014e, 0xe014f, 0xe0150, + 0xe0151, 0xe0152, 0xe0153, 0xe0154, 0xe0155, 0xe0156, 0xe0157, 0xe0158, + 0xe0159, 0xe015a, 0xe015b, 0xe015c, 0xe015d, 0xe015e, 0xe015f, 0xe0160, + 0xe0161, 0xe0162, 0xe0163, 0xe0164, 0xe0165, 0xe0166, 0xe0167, 0xe0168, + 0xe0169, 0xe016a, 0xe016b, 0xe016c, 0xe016d, 0xe016e, 0xe016f, 0xe0170, + 0xe0171, 0xe0172, 0xe0173, 0xe0174, 0xe0175, 0xe0176, 0xe0177, 0xe0178, + 0xe0179, 0xe017a, 0xe017b, 0xe017c, 0xe017d, 0xe017e, 0xe017f, 0xe0180, + 0xe0181, 0xe0182, 0xe0183, 0xe0184, 0xe0185, 0xe0186, 0xe0187, 0xe0188, + 0xe0189, 0xe018a, 0xe018b, 0xe018c, 0xe018d, 0xe018e, 0xe018f, 0xe0190, + 0xe0191, 0xe0192, 0xe0193, 0xe0194, 0xe0195, 0xe0196, 0xe0197, 0xe0198, + 0xe0199, 0xe019a, 0xe019b, 0xe019c, 0xe019d, 0xe019e, 0xe019f, 0xe01a0, + 0xe01a1, 0xe01a2, 0xe01a3, 0xe01a4, 0xe01a5, 0xe01a6, 0xe01a7, 0xe01a8, + 0xe01a9, 0xe01aa, 0xe01ab, 0xe01ac, 0xe01ad, 0xe01ae, 0xe01af, 0xe01b0, + 0xe01b1, 0xe01b2, 0xe01b3, 0xe01b4, 0xe01b5, 0xe01b6, 0xe01b7, 0xe01b8, + 0xe01b9, 0xe01ba, 0xe01bb, 0xe01bc, 0xe01bd, 0xe01be, 0xe01bf, 0xe01c0, + 0xe01c1, 0xe01c2, 0xe01c3, 0xe01c4, 0xe01c5, 0xe01c6, 0xe01c7, 0xe01c8, + 0xe01c9, 0xe01ca, 0xe01cb, 0xe01cc, 0xe01cd, 0xe01ce, 0xe01cf, 0xe01d0, + 0xe01d1, 0xe01d2, 0xe01d3, 0xe01d4, 0xe01d5, 0xe01d6, 0xe01d7, 0xe01d8, + 0xe01d9, 0xe01da, 0xe01db, 0xe01dc, 0xe01dd, 0xe01de, 0xe01df, 0xe01e0, + 0xe01e1, 0xe01e2, 0xe01e3, 0xe01e4, 0xe01e5, 0xe01e6, 0xe01e7, 0xe01e8, + 0xe01e9, 0xe01ea, 0xe01eb, 0xe01ec, 0xe01ed, 0xe01ee, 0xe01ef}; + if (std::binary_search(std::begin(combining), std::end(combining), + label.front())) { + return false; + } + // We verify this next step as part of the mapping: + // --------------------------------------------- + // Each code point in the label must only have certain status values + // according to Section 5, IDNA Mapping Table: + // - For Transitional Processing, each value must be valid. + // - For Nontransitional Processing, each value must be either valid or + // deviation. + + // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix + // A, in The Unicode Code Points and Internationalized Domain Names for + // Applications (IDNA) [IDNA2008]. + constexpr static uint32_t virama[] = { + 0x094D, 0x09CD, 0x0A4D, 0x0ACD, 0x0B4D, 0x0BCD, 0x0C4D, 0x0CCD, + 0x0D3B, 0x0D3C, 0x0D4D, 0x0DCA, 0x0E3A, 0x0EBA, 0x0F84, 0x1039, + 0x103A, 0x1714, 0x1734, 0x17D2, 0x1A60, 0x1B44, 0x1BAA, 0x1BAB, + 0x1BF2, 0x1BF3, 0x2D7F, 0xA806, 0xA82C, 0xA8C4, 0xA953, 0xA9C0, + 0xAAF6, 0xABED, 0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134, + 0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F, + 0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47, + 0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97}; + constexpr static uint32_t R[] = { + 0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631, + 0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688, + 0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691, + 0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0, + 0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb, + 0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715, + 0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f, + 0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac}; + constexpr static uint32_t L[] = {0xa872}; + constexpr static uint32_t D[] = { + 0x620, 0x626, 0x628, 0x62a, 0x62b, 0x62c, 0x62d, 0x62e, 0x633, + 0x634, 0x635, 0x636, 0x637, 0x638, 0x639, 0x63a, 0x63b, 0x63c, + 0x63d, 0x63e, 0x63f, 0x641, 0x642, 0x643, 0x644, 0x645, 0x646, + 0x647, 0x649, 0x64a, 0x66e, 0x66f, 0x678, 0x679, 0x67a, 0x67b, + 0x67c, 0x67d, 0x67e, 0x67f, 0x680, 0x681, 0x682, 0x683, 0x684, + 0x685, 0x686, 0x687, 0x69a, 0x69b, 0x69c, 0x69d, 0x69e, 0x69f, + 0x6a0, 0x6a1, 0x6a2, 0x6a3, 0x6a4, 0x6a5, 0x6a6, 0x6a7, 0x6a8, + 0x6a9, 0x6aa, 0x6ab, 0x6ac, 0x6ad, 0x6ae, 0x6af, 0x6b0, 0x6b1, + 0x6b2, 0x6b3, 0x6b4, 0x6b5, 0x6b6, 0x6b7, 0x6b8, 0x6b9, 0x6ba, + 0x6bb, 0x6bc, 0x6bd, 0x6be, 0x6bf, 0x6c1, 0x6c2, 0x6cc, 0x6ce, + 0x6d0, 0x6d1, 0x6fa, 0x6fb, 0x6fc, 0x6ff, 0x712, 0x713, 0x714, + 0x71a, 0x71b, 0x71c, 0x71d, 0x71f, 0x720, 0x721, 0x722, 0x723, + 0x724, 0x725, 0x726, 0x727, 0x729, 0x72b, 0x72d, 0x72e, 0x74e, + 0x74f, 0x750, 0x751, 0x752, 0x753, 0x754, 0x755, 0x756, 0x757, + 0x758, 0x75c, 0x75d, 0x75e, 0x75f, 0x760, 0x761, 0x762, 0x763, + 0x764, 0x765, 0x766, 0x850, 0x851, 0x852, 0x853, 0x855, 0x8a0, + 0x8a2, 0x8a3, 0x8a4, 0x8a5, 0x8a6, 0x8a7, 0x8a8, 0x8a9, 0x1807, + 0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828, + 0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831, + 0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a, + 0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843, + 0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c, + 0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855, + 0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e, + 0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867, + 0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870, + 0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888, + 0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891, + 0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a, + 0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3, + 0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842, + 0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b, + 0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854, + 0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d, + 0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866, + 0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f, + 0xa870, 0xa871}; + + for (size_t i = 0; i < label.size(); i++) { + uint32_t c = label[i]; + if (c == 0x200c) { + if (i > 0) { + if (std::binary_search(std::begin(virama), std::end(virama), + label[i - 1])) { + return true; + } + } + if ((i == 0) || (i + 1 >= label.size())) { + return false; + } + // we go backward looking for L or D + auto is_l_or_d = [](uint32_t code) { + return std::binary_search(std::begin(L), std::end(L), code) || + std::binary_search(std::begin(D), std::end(D), code); + }; + auto is_r_or_d = [](uint32_t code) { + return std::binary_search(std::begin(R), std::end(R), code) || + std::binary_search(std::begin(D), std::end(D), code); + }; + std::u32string_view before = label.substr(0, i); + std::u32string_view after = label.substr(i + 1); + return (std::find_if(before.begin(), before.end(), is_l_or_d) != + before.end()) && + (std::find_if(after.begin(), after.end(), is_r_or_d) != + after.end()); + } else if (c == 0x200d) { + if (i > 0) { + if (std::binary_search(std::begin(virama), std::end(virama), + label[i - 1])) { + return true; + } + } + return false; + } + } + + // If CheckBidi, and if the domain name is a Bidi domain name, then the label + // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, + // Section 2. + + // The following rule, consisting of six conditions, applies to labels + // in Bidi domain names. The requirements that this rule satisfies are + // described in Section 3. All of the conditions must be satisfied for + // the rule to be satisfied. + // + // 1. The first character must be a character with Bidi property L, R, + // or AL. If it has the R or AL property, it is an RTL label; if it + // has the L property, it is an LTR label. + // + // 2. In an RTL label, only characters with the Bidi properties R, AL, + // AN, EN, ES, CS, ET, ON, BN, or NSM are allowed. + // + // 3. In an RTL label, the end of the label must be a character with + // Bidi property R, AL, EN, or AN, followed by zero or more + // characters with Bidi property NSM. + // + // 4. In an RTL label, if an EN is present, no AN may be present, and + // vice versa. + // + // 5. In an LTR label, only characters with the Bidi properties L, EN, + // ES, CS, ET, ON, BN, or NSM are allowed. + // + // 6. In an LTR label, the end of the label must be a character with + // Bidi property L or EN, followed by zero or more characters with + // Bidi property NSM. + + size_t last_non_nsm_char = find_last_not_of_nsm(label); + if (last_non_nsm_char == std::u32string_view::npos) { + return false; + } + + // A "Bidi domain name" is a domain name that contains at least one RTL label. + // The following rule, consisting of six conditions, applies to labels in Bidi + // domain names. + if (is_rtl_label(label)) { + // The first character must be a character with Bidi property L, R, + // or AL. If it has the R or AL property, it is an RTL label; if it + // has the L property, it is an LTR label. + + if (find_direction(label[0]) == direction::L) { + // Eval as LTR + + // In an LTR label, only characters with the Bidi properties L, EN, + // ES, CS, ET, ON, BN, or NSM are allowed. + for (size_t i = 0; i < last_non_nsm_char; i++) { + const direction d = find_direction(label[i]); + if (!(d == direction::L || d == direction::EN || d == direction::ES || + d == direction::CS || d == direction::ET || d == direction::ON || + d == direction::BN || d == direction::NSM)) { + return false; + } + + if ((i == last_non_nsm_char) && + !(d == direction::L || d == direction::EN)) { + return false; + } + } + + return true; + + } else { + // Eval as RTL + + bool has_an = false; + bool has_en = false; + for (size_t i = 0; i <= last_non_nsm_char; i++) { + const direction d = find_direction(label[i]); + + // In an RTL label, if an EN is present, no AN may be present, and vice + // versa. + if ((d == direction::EN && ((has_en = true) && has_an)) || + (d == direction::AN && ((has_an = true) && has_en))) { + return false; + } + + if (!(d == direction::R || d == direction::AL || d == direction::AN || + d == direction::EN || d == direction::ES || d == direction::CS || + d == direction::ET || d == direction::ON || d == direction::BN || + d == direction::NSM)) { + return false; + } + + if (i == last_non_nsm_char && + !(d == direction::R || d == direction::AL || d == direction::AN || + d == direction::EN)) { + return false; + } + } + + return true; + } + } + + return true; +} + +} // namespace ada::idna +/* end file src/validity.cpp */ +/* begin file src/to_ascii.cpp */ + +#include +#include + + +namespace ada::idna { + +bool constexpr is_ascii(std::u32string_view view) { + for (uint32_t c : view) { + if (c >= 0x80) { + return false; + } + } + return true; +} + +bool constexpr is_ascii(std::string_view view) { + for (uint8_t c : view) { + if (c >= 0x80) { + return false; + } + } + return true; +} + +constexpr static uint8_t is_forbidden_domain_code_point_table[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + +static_assert(sizeof(is_forbidden_domain_code_point_table) == 256); + +inline bool is_forbidden_domain_code_point(const char c) noexcept { + return is_forbidden_domain_code_point_table[uint8_t(c)]; +} + +bool contains_forbidden_domain_code_point(std::string_view view) { + return ( + std::any_of(view.begin(), view.end(), is_forbidden_domain_code_point)); +} + +// We return "" on error. +static std::string from_ascii_to_ascii(std::string_view ut8_string) { + static const std::string error = ""; + // copy and map + // we could be more efficient by avoiding the copy when unnecessary. + std::string mapped_string = std::string(ut8_string); + ascii_map(mapped_string.data(), mapped_string.size()); + std::string out; + size_t label_start = 0; + + while (label_start != mapped_string.size()) { + size_t loc_dot = mapped_string.find('.', label_start); + bool is_last_label = (loc_dot == std::string_view::npos); + size_t label_size = is_last_label ? mapped_string.size() - label_start + : loc_dot - label_start; + size_t label_size_with_dot = is_last_label ? label_size : label_size + 1; + std::string_view label_view(mapped_string.data() + label_start, label_size); + label_start += label_size_with_dot; + if (label_size == 0) { + // empty label? Nothing to do. + } else if (label_view.starts_with("xn--")) { + // The xn-- part is the expensive game. + out.append(label_view); + std::string_view puny_segment_ascii( + out.data() + out.size() - label_view.size() + 4, + label_view.size() - 4); + std::u32string tmp_buffer; + bool is_ok = ada::idna::punycode_to_utf32(puny_segment_ascii, tmp_buffer); + if (!is_ok) { + return error; + } + std::u32string post_map = ada::idna::map(tmp_buffer); + if (tmp_buffer != post_map) { + return error; + } + std::u32string pre_normal = post_map; + normalize(post_map); + if (post_map != pre_normal) { + return error; + } + if (post_map.empty()) { + return error; + } + if (!is_label_valid(post_map)) { + return error; + } + } else { + out.append(label_view); + } + if (!is_last_label) { + out.push_back('.'); + } + } + return out; +} + +// We return "" on error. +std::string to_ascii(std::string_view ut8_string) { + if (is_ascii(ut8_string)) { + return from_ascii_to_ascii(ut8_string); + } + static const std::string error = ""; + // We convert to UTF-32 + size_t utf32_length = + ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size()); + std::u32string utf32(utf32_length, '\0'); + size_t actual_utf32_length = ada::idna::utf8_to_utf32( + ut8_string.data(), ut8_string.size(), utf32.data()); + if (actual_utf32_length == 0) { + return error; + } + // mapping + utf32 = ada::idna::map(utf32); + normalize(utf32); + std::string out; + size_t label_start = 0; + + while (label_start != utf32.size()) { + size_t loc_dot = utf32.find('.', label_start); + bool is_last_label = (loc_dot == std::string_view::npos); + size_t label_size = + is_last_label ? utf32.size() - label_start : loc_dot - label_start; + size_t label_size_with_dot = is_last_label ? label_size : label_size + 1; + std::u32string_view label_view(utf32.data() + label_start, label_size); + label_start += label_size_with_dot; + if (label_size == 0) { + // empty label? Nothing to do. + } else if (label_view.starts_with(U"xn--")) { + // we do not need to check, e.g., Xn-- because mapping goes to lower case + for (char32_t c : label_view) { + if (c >= 0x80) { + return error; + } + out += (unsigned char)(c); + } + std::string_view puny_segment_ascii( + out.data() + out.size() - label_view.size() + 4, + label_view.size() - 4); + std::u32string tmp_buffer; + bool is_ok = ada::idna::punycode_to_utf32(puny_segment_ascii, tmp_buffer); + if (!is_ok) { + return error; + } + std::u32string post_map = ada::idna::map(tmp_buffer); + if (tmp_buffer != post_map) { + return error; + } + std::u32string pre_normal = post_map; + normalize(post_map); + if (post_map != pre_normal) { + return error; + } + if (post_map.empty()) { + return error; + } + if (!is_label_valid(post_map)) { + return error; + } + } else { + // The fast path here is an ascii label. + if (is_ascii(label_view)) { + // no validation needed. + for (char32_t c : label_view) { + out += (unsigned char)(c); + } + } else { + // slow path. + // first check validity. + if (!is_label_valid(label_view)) { + return error; + } + // It is valid! So now we must encode it as punycode... + out.append("xn--"); + bool is_ok = ada::idna::utf32_to_punycode(label_view, out); + if (!is_ok) { + return error; + } + } + } + if (!is_last_label) { + out.push_back('.'); + } + } + return out; +} +} // namespace ada::idna +/* end file src/to_ascii.cpp */ +/* begin file src/to_unicode.cpp */ + +#include +#include + + +namespace ada::idna { +std::string to_unicode(std::string_view input) { + std::string output; + output.reserve(input.size()); + + size_t label_start = 0; + while (label_start < input.size()) { + size_t loc_dot = input.find('.', label_start); + bool is_last_label = (loc_dot == std::string_view::npos); + size_t label_size = + is_last_label ? input.size() - label_start : loc_dot - label_start; + auto label_view = std::string_view(input.data() + label_start, label_size); + + if (label_view.starts_with("xn--") && ada::idna::is_ascii(label_view)) { + label_view.remove_prefix(4); + if (ada::idna::verify_punycode(label_view)) { + std::u32string tmp_buffer; + if (ada::idna::punycode_to_utf32(label_view, tmp_buffer)) { + auto utf8_size = ada::idna::utf8_length_from_utf32(tmp_buffer.data(), + tmp_buffer.size()); + std::string final_utf8(utf8_size, '\0'); + ada::idna::utf32_to_utf8(tmp_buffer.data(), tmp_buffer.size(), + final_utf8.data()); + output.append(final_utf8); + } else { + // ToUnicode never fails. If any step fails, then the original input + // sequence is returned immediately in that step. + output.append( + std::string_view(input.data() + label_start, label_size)); + } + } else { + output.append(std::string_view(input.data() + label_start, label_size)); + } + } else { + output.append(label_view); + } + + if (!is_last_label) { + output.push_back('.'); + } + + label_start += label_size + 1; + } + + return output; +} +} // namespace ada::idna +/* end file src/to_unicode.cpp */ +/* begin file src/identifier.cpp */ + +#include +#include +#include + +/* begin file src/id_tables.cpp */ +// IDNA 15.1.0 + +// clang-format off +#ifndef ADA_IDNA_IDENTIFIER_TABLES_H +#define ADA_IDNA_IDENTIFIER_TABLES_H +#include + +namespace ada::idna { + +const uint32_t id_continue[1344][2] = +{ + {48, 57}, {65, 90}, {95, 95}, {97, 122}, + {170, 170}, {181, 181}, {183, 183}, {186, 186}, + {192, 214}, {216, 246}, {248, 442}, {443, 443}, + {444, 447}, {448, 451}, {452, 659}, {660, 660}, + {661, 687}, {688, 705}, {710, 721}, {736, 740}, + {748, 748}, {750, 750}, {768, 879}, {880, 883}, + {884, 884}, {886, 887}, {890, 890}, {891, 893}, + {895, 895}, {902, 902}, {903, 903}, {904, 906}, + {908, 908}, {910, 929}, {931, 1013}, {1015, 1153}, + {1155, 1159}, {1162, 1327}, {1329, 1366}, {1369, 1369}, + {1376, 1416}, {1425, 1469}, {1471, 1471}, {1473, 1474}, + {1476, 1477}, {1479, 1479}, {1488, 1514}, {1519, 1522}, + {1552, 1562}, {1568, 1599}, {1600, 1600}, {1601, 1610}, + {1611, 1631}, {1632, 1641}, {1646, 1647}, {1648, 1648}, + {1649, 1747}, {1749, 1749}, {1750, 1756}, {1759, 1764}, + {1765, 1766}, {1767, 1768}, {1770, 1773}, {1774, 1775}, + {1776, 1785}, {1786, 1788}, {1791, 1791}, {1808, 1808}, + {1809, 1809}, {1810, 1839}, {1840, 1866}, {1869, 1957}, + {1958, 1968}, {1969, 1969}, {1984, 1993}, {1994, 2026}, + {2027, 2035}, {2036, 2037}, {2042, 2042}, {2045, 2045}, + {2048, 2069}, {2070, 2073}, {2074, 2074}, {2075, 2083}, + {2084, 2084}, {2085, 2087}, {2088, 2088}, {2089, 2093}, + {2112, 2136}, {2137, 2139}, {2144, 2154}, {2160, 2183}, + {2185, 2190}, {2200, 2207}, {2208, 2248}, {2249, 2249}, + {2250, 2273}, {2275, 2306}, {2307, 2307}, {2308, 2361}, + {2362, 2362}, {2363, 2363}, {2364, 2364}, {2365, 2365}, + {2366, 2368}, {2369, 2376}, {2377, 2380}, {2381, 2381}, + {2382, 2383}, {2384, 2384}, {2385, 2391}, {2392, 2401}, + {2402, 2403}, {2406, 2415}, {2417, 2417}, {2418, 2432}, + {2433, 2433}, {2434, 2435}, {2437, 2444}, {2447, 2448}, + {2451, 2472}, {2474, 2480}, {2482, 2482}, {2486, 2489}, + {2492, 2492}, {2493, 2493}, {2494, 2496}, {2497, 2500}, + {2503, 2504}, {2507, 2508}, {2509, 2509}, {2510, 2510}, + {2519, 2519}, {2524, 2525}, {2527, 2529}, {2530, 2531}, + {2534, 2543}, {2544, 2545}, {2556, 2556}, {2558, 2558}, + {2561, 2562}, {2563, 2563}, {2565, 2570}, {2575, 2576}, + {2579, 2600}, {2602, 2608}, {2610, 2611}, {2613, 2614}, + {2616, 2617}, {2620, 2620}, {2622, 2624}, {2625, 2626}, + {2631, 2632}, {2635, 2637}, {2641, 2641}, {2649, 2652}, + {2654, 2654}, {2662, 2671}, {2672, 2673}, {2674, 2676}, + {2677, 2677}, {2689, 2690}, {2691, 2691}, {2693, 2701}, + {2703, 2705}, {2707, 2728}, {2730, 2736}, {2738, 2739}, + {2741, 2745}, {2748, 2748}, {2749, 2749}, {2750, 2752}, + {2753, 2757}, {2759, 2760}, {2761, 2761}, {2763, 2764}, + {2765, 2765}, {2768, 2768}, {2784, 2785}, {2786, 2787}, + {2790, 2799}, {2809, 2809}, {2810, 2815}, {2817, 2817}, + {2818, 2819}, {2821, 2828}, {2831, 2832}, {2835, 2856}, + {2858, 2864}, {2866, 2867}, {2869, 2873}, {2876, 2876}, + {2877, 2877}, {2878, 2878}, {2879, 2879}, {2880, 2880}, + {2881, 2884}, {2887, 2888}, {2891, 2892}, {2893, 2893}, + {2901, 2902}, {2903, 2903}, {2908, 2909}, {2911, 2913}, + {2914, 2915}, {2918, 2927}, {2929, 2929}, {2946, 2946}, + {2947, 2947}, {2949, 2954}, {2958, 2960}, {2962, 2965}, + {2969, 2970}, {2972, 2972}, {2974, 2975}, {2979, 2980}, + {2984, 2986}, {2990, 3001}, {3006, 3007}, {3008, 3008}, + {3009, 3010}, {3014, 3016}, {3018, 3020}, {3021, 3021}, + {3024, 3024}, {3031, 3031}, {3046, 3055}, {3072, 3072}, + {3073, 3075}, {3076, 3076}, {3077, 3084}, {3086, 3088}, + {3090, 3112}, {3114, 3129}, {3132, 3132}, {3133, 3133}, + {3134, 3136}, {3137, 3140}, {3142, 3144}, {3146, 3149}, + {3157, 3158}, {3160, 3162}, {3165, 3165}, {3168, 3169}, + {3170, 3171}, {3174, 3183}, {3200, 3200}, {3201, 3201}, + {3202, 3203}, {3205, 3212}, {3214, 3216}, {3218, 3240}, + {3242, 3251}, {3253, 3257}, {3260, 3260}, {3261, 3261}, + {3262, 3262}, {3263, 3263}, {3264, 3268}, {3270, 3270}, + {3271, 3272}, {3274, 3275}, {3276, 3277}, {3285, 3286}, + {3293, 3294}, {3296, 3297}, {3298, 3299}, {3302, 3311}, + {3313, 3314}, {3315, 3315}, {3328, 3329}, {3330, 3331}, + {3332, 3340}, {3342, 3344}, {3346, 3386}, {3387, 3388}, + {3389, 3389}, {3390, 3392}, {3393, 3396}, {3398, 3400}, + {3402, 3404}, {3405, 3405}, {3406, 3406}, {3412, 3414}, + {3415, 3415}, {3423, 3425}, {3426, 3427}, {3430, 3439}, + {3450, 3455}, {3457, 3457}, {3458, 3459}, {3461, 3478}, + {3482, 3505}, {3507, 3515}, {3517, 3517}, {3520, 3526}, + {3530, 3530}, {3535, 3537}, {3538, 3540}, {3542, 3542}, + {3544, 3551}, {3558, 3567}, {3570, 3571}, {3585, 3632}, + {3633, 3633}, {3634, 3635}, {3636, 3642}, {3648, 3653}, + {3654, 3654}, {3655, 3662}, {3664, 3673}, {3713, 3714}, + {3716, 3716}, {3718, 3722}, {3724, 3747}, {3749, 3749}, + {3751, 3760}, {3761, 3761}, {3762, 3763}, {3764, 3772}, + {3773, 3773}, {3776, 3780}, {3782, 3782}, {3784, 3790}, + {3792, 3801}, {3804, 3807}, {3840, 3840}, {3864, 3865}, + {3872, 3881}, {3893, 3893}, {3895, 3895}, {3897, 3897}, + {3902, 3903}, {3904, 3911}, {3913, 3948}, {3953, 3966}, + {3967, 3967}, {3968, 3972}, {3974, 3975}, {3976, 3980}, + {3981, 3991}, {3993, 4028}, {4038, 4038}, {4096, 4138}, + {4139, 4140}, {4141, 4144}, {4145, 4145}, {4146, 4151}, + {4152, 4152}, {4153, 4154}, {4155, 4156}, {4157, 4158}, + {4159, 4159}, {4160, 4169}, {4176, 4181}, {4182, 4183}, + {4184, 4185}, {4186, 4189}, {4190, 4192}, {4193, 4193}, + {4194, 4196}, {4197, 4198}, {4199, 4205}, {4206, 4208}, + {4209, 4212}, {4213, 4225}, {4226, 4226}, {4227, 4228}, + {4229, 4230}, {4231, 4236}, {4237, 4237}, {4238, 4238}, + {4239, 4239}, {4240, 4249}, {4250, 4252}, {4253, 4253}, + {4256, 4293}, {4295, 4295}, {4301, 4301}, {4304, 4346}, + {4348, 4348}, {4349, 4351}, {4352, 4680}, {4682, 4685}, + {4688, 4694}, {4696, 4696}, {4698, 4701}, {4704, 4744}, + {4746, 4749}, {4752, 4784}, {4786, 4789}, {4792, 4798}, + {4800, 4800}, {4802, 4805}, {4808, 4822}, {4824, 4880}, + {4882, 4885}, {4888, 4954}, {4957, 4959}, {4969, 4977}, + {4992, 5007}, {5024, 5109}, {5112, 5117}, {5121, 5740}, + {5743, 5759}, {5761, 5786}, {5792, 5866}, {5870, 5872}, + {5873, 5880}, {5888, 5905}, {5906, 5908}, {5909, 5909}, + {5919, 5937}, {5938, 5939}, {5940, 5940}, {5952, 5969}, + {5970, 5971}, {5984, 5996}, {5998, 6000}, {6002, 6003}, + {6016, 6067}, {6068, 6069}, {6070, 6070}, {6071, 6077}, + {6078, 6085}, {6086, 6086}, {6087, 6088}, {6089, 6099}, + {6103, 6103}, {6108, 6108}, {6109, 6109}, {6112, 6121}, + {6155, 6157}, {6159, 6159}, {6160, 6169}, {6176, 6210}, + {6211, 6211}, {6212, 6264}, {6272, 6276}, {6277, 6278}, + {6279, 6312}, {6313, 6313}, {6314, 6314}, {6320, 6389}, + {6400, 6430}, {6432, 6434}, {6435, 6438}, {6439, 6440}, + {6441, 6443}, {6448, 6449}, {6450, 6450}, {6451, 6456}, + {6457, 6459}, {6470, 6479}, {6480, 6509}, {6512, 6516}, + {6528, 6571}, {6576, 6601}, {6608, 6617}, {6618, 6618}, + {6656, 6678}, {6679, 6680}, {6681, 6682}, {6683, 6683}, + {6688, 6740}, {6741, 6741}, {6742, 6742}, {6743, 6743}, + {6744, 6750}, {6752, 6752}, {6753, 6753}, {6754, 6754}, + {6755, 6756}, {6757, 6764}, {6765, 6770}, {6771, 6780}, + {6783, 6783}, {6784, 6793}, {6800, 6809}, {6823, 6823}, + {6832, 6845}, {6847, 6862}, {6912, 6915}, {6916, 6916}, + {6917, 6963}, {6964, 6964}, {6965, 6965}, {6966, 6970}, + {6971, 6971}, {6972, 6972}, {6973, 6977}, {6978, 6978}, + {6979, 6980}, {6981, 6988}, {6992, 7001}, {7019, 7027}, + {7040, 7041}, {7042, 7042}, {7043, 7072}, {7073, 7073}, + {7074, 7077}, {7078, 7079}, {7080, 7081}, {7082, 7082}, + {7083, 7085}, {7086, 7087}, {7088, 7097}, {7098, 7141}, + {7142, 7142}, {7143, 7143}, {7144, 7145}, {7146, 7148}, + {7149, 7149}, {7150, 7150}, {7151, 7153}, {7154, 7155}, + {7168, 7203}, {7204, 7211}, {7212, 7219}, {7220, 7221}, + {7222, 7223}, {7232, 7241}, {7245, 7247}, {7248, 7257}, + {7258, 7287}, {7288, 7293}, {7296, 7304}, {7312, 7354}, + {7357, 7359}, {7376, 7378}, {7380, 7392}, {7393, 7393}, + {7394, 7400}, {7401, 7404}, {7405, 7405}, {7406, 7411}, + {7412, 7412}, {7413, 7414}, {7415, 7415}, {7416, 7417}, + {7418, 7418}, {7424, 7467}, {7468, 7530}, {7531, 7543}, + {7544, 7544}, {7545, 7578}, {7579, 7615}, {7616, 7679}, + {7680, 7957}, {7960, 7965}, {7968, 8005}, {8008, 8013}, + {8016, 8023}, {8025, 8025}, {8027, 8027}, {8029, 8029}, + {8031, 8061}, {8064, 8116}, {8118, 8124}, {8126, 8126}, + {8130, 8132}, {8134, 8140}, {8144, 8147}, {8150, 8155}, + {8160, 8172}, {8178, 8180}, {8182, 8188}, {8204, 8205}, + {8255, 8256}, {8276, 8276}, {8305, 8305}, {8319, 8319}, + {8336, 8348}, {8400, 8412}, {8417, 8417}, {8421, 8432}, + {8450, 8450}, {8455, 8455}, {8458, 8467}, {8469, 8469}, + {8472, 8472}, {8473, 8477}, {8484, 8484}, {8486, 8486}, + {8488, 8488}, {8490, 8493}, {8494, 8494}, {8495, 8500}, + {8501, 8504}, {8505, 8505}, {8508, 8511}, {8517, 8521}, + {8526, 8526}, {8544, 8578}, {8579, 8580}, {8581, 8584}, + {11264, 11387}, {11388, 11389}, {11390, 11492}, {11499, 11502}, + {11503, 11505}, {11506, 11507}, {11520, 11557}, {11559, 11559}, + {11565, 11565}, {11568, 11623}, {11631, 11631}, {11647, 11647}, + {11648, 11670}, {11680, 11686}, {11688, 11694}, {11696, 11702}, + {11704, 11710}, {11712, 11718}, {11720, 11726}, {11728, 11734}, + {11736, 11742}, {11744, 11775}, {12293, 12293}, {12294, 12294}, + {12295, 12295}, {12321, 12329}, {12330, 12333}, {12334, 12335}, + {12337, 12341}, {12344, 12346}, {12347, 12347}, {12348, 12348}, + {12353, 12438}, {12441, 12442}, {12443, 12444}, {12445, 12446}, + {12447, 12447}, {12449, 12538}, {12539, 12539}, {12540, 12542}, + {12543, 12543}, {12549, 12591}, {12593, 12686}, {12704, 12735}, + {12784, 12799}, {13312, 19903}, {19968, 40980}, {40981, 40981}, + {40982, 42124}, {42192, 42231}, {42232, 42237}, {42240, 42507}, + {42508, 42508}, {42512, 42527}, {42528, 42537}, {42538, 42539}, + {42560, 42605}, {42606, 42606}, {42607, 42607}, {42612, 42621}, + {42623, 42623}, {42624, 42651}, {42652, 42653}, {42654, 42655}, + {42656, 42725}, {42726, 42735}, {42736, 42737}, {42775, 42783}, + {42786, 42863}, {42864, 42864}, {42865, 42887}, {42888, 42888}, + {42891, 42894}, {42895, 42895}, {42896, 42954}, {42960, 42961}, + {42963, 42963}, {42965, 42969}, {42994, 42996}, {42997, 42998}, + {42999, 42999}, {43000, 43001}, {43002, 43002}, {43003, 43009}, + {43010, 43010}, {43011, 43013}, {43014, 43014}, {43015, 43018}, + {43019, 43019}, {43020, 43042}, {43043, 43044}, {43045, 43046}, + {43047, 43047}, {43052, 43052}, {43072, 43123}, {43136, 43137}, + {43138, 43187}, {43188, 43203}, {43204, 43205}, {43216, 43225}, + {43232, 43249}, {43250, 43255}, {43259, 43259}, {43261, 43262}, + {43263, 43263}, {43264, 43273}, {43274, 43301}, {43302, 43309}, + {43312, 43334}, {43335, 43345}, {43346, 43347}, {43360, 43388}, + {43392, 43394}, {43395, 43395}, {43396, 43442}, {43443, 43443}, + {43444, 43445}, {43446, 43449}, {43450, 43451}, {43452, 43453}, + {43454, 43456}, {43471, 43471}, {43472, 43481}, {43488, 43492}, + {43493, 43493}, {43494, 43494}, {43495, 43503}, {43504, 43513}, + {43514, 43518}, {43520, 43560}, {43561, 43566}, {43567, 43568}, + {43569, 43570}, {43571, 43572}, {43573, 43574}, {43584, 43586}, + {43587, 43587}, {43588, 43595}, {43596, 43596}, {43597, 43597}, + {43600, 43609}, {43616, 43631}, {43632, 43632}, {43633, 43638}, + {43642, 43642}, {43643, 43643}, {43644, 43644}, {43645, 43645}, + {43646, 43695}, {43696, 43696}, {43697, 43697}, {43698, 43700}, + {43701, 43702}, {43703, 43704}, {43705, 43709}, {43710, 43711}, + {43712, 43712}, {43713, 43713}, {43714, 43714}, {43739, 43740}, + {43741, 43741}, {43744, 43754}, {43755, 43755}, {43756, 43757}, + {43758, 43759}, {43762, 43762}, {43763, 43764}, {43765, 43765}, + {43766, 43766}, {43777, 43782}, {43785, 43790}, {43793, 43798}, + {43808, 43814}, {43816, 43822}, {43824, 43866}, {43868, 43871}, + {43872, 43880}, {43881, 43881}, {43888, 43967}, {43968, 44002}, + {44003, 44004}, {44005, 44005}, {44006, 44007}, {44008, 44008}, + {44009, 44010}, {44012, 44012}, {44013, 44013}, {44016, 44025}, + {44032, 55203}, {55216, 55238}, {55243, 55291}, {63744, 64109}, + {64112, 64217}, {64256, 64262}, {64275, 64279}, {64285, 64285}, + {64286, 64286}, {64287, 64296}, {64298, 64310}, {64312, 64316}, + {64318, 64318}, {64320, 64321}, {64323, 64324}, {64326, 64433}, + {64467, 64829}, {64848, 64911}, {64914, 64967}, {65008, 65019}, + {65024, 65039}, {65056, 65071}, {65075, 65076}, {65101, 65103}, + {65136, 65140}, {65142, 65276}, {65296, 65305}, {65313, 65338}, + {65343, 65343}, {65345, 65370}, {65381, 65381}, {65382, 65391}, + {65392, 65392}, {65393, 65437}, {65438, 65439}, {65440, 65470}, + {65474, 65479}, {65482, 65487}, {65490, 65495}, {65498, 65500}, + {65536, 65547}, {65549, 65574}, {65576, 65594}, {65596, 65597}, + {65599, 65613}, {65616, 65629}, {65664, 65786}, {65856, 65908}, + {66045, 66045}, {66176, 66204}, {66208, 66256}, {66272, 66272}, + {66304, 66335}, {66349, 66368}, {66369, 66369}, {66370, 66377}, + {66378, 66378}, {66384, 66421}, {66422, 66426}, {66432, 66461}, + {66464, 66499}, {66504, 66511}, {66513, 66517}, {66560, 66639}, + {66640, 66717}, {66720, 66729}, {66736, 66771}, {66776, 66811}, + {66816, 66855}, {66864, 66915}, {66928, 66938}, {66940, 66954}, + {66956, 66962}, {66964, 66965}, {66967, 66977}, {66979, 66993}, + {66995, 67001}, {67003, 67004}, {67072, 67382}, {67392, 67413}, + {67424, 67431}, {67456, 67461}, {67463, 67504}, {67506, 67514}, + {67584, 67589}, {67592, 67592}, {67594, 67637}, {67639, 67640}, + {67644, 67644}, {67647, 67669}, {67680, 67702}, {67712, 67742}, + {67808, 67826}, {67828, 67829}, {67840, 67861}, {67872, 67897}, + {67968, 68023}, {68030, 68031}, {68096, 68096}, {68097, 68099}, + {68101, 68102}, {68108, 68111}, {68112, 68115}, {68117, 68119}, + {68121, 68149}, {68152, 68154}, {68159, 68159}, {68192, 68220}, + {68224, 68252}, {68288, 68295}, {68297, 68324}, {68325, 68326}, + {68352, 68405}, {68416, 68437}, {68448, 68466}, {68480, 68497}, + {68608, 68680}, {68736, 68786}, {68800, 68850}, {68864, 68899}, + {68900, 68903}, {68912, 68921}, {69248, 69289}, {69291, 69292}, + {69296, 69297}, {69373, 69375}, {69376, 69404}, {69415, 69415}, + {69424, 69445}, {69446, 69456}, {69488, 69505}, {69506, 69509}, + {69552, 69572}, {69600, 69622}, {69632, 69632}, {69633, 69633}, + {69634, 69634}, {69635, 69687}, {69688, 69702}, {69734, 69743}, + {69744, 69744}, {69745, 69746}, {69747, 69748}, {69749, 69749}, + {69759, 69761}, {69762, 69762}, {69763, 69807}, {69808, 69810}, + {69811, 69814}, {69815, 69816}, {69817, 69818}, {69826, 69826}, + {69840, 69864}, {69872, 69881}, {69888, 69890}, {69891, 69926}, + {69927, 69931}, {69932, 69932}, {69933, 69940}, {69942, 69951}, + {69956, 69956}, {69957, 69958}, {69959, 69959}, {69968, 70002}, + {70003, 70003}, {70006, 70006}, {70016, 70017}, {70018, 70018}, + {70019, 70066}, {70067, 70069}, {70070, 70078}, {70079, 70080}, + {70081, 70084}, {70089, 70092}, {70094, 70094}, {70095, 70095}, + {70096, 70105}, {70106, 70106}, {70108, 70108}, {70144, 70161}, + {70163, 70187}, {70188, 70190}, {70191, 70193}, {70194, 70195}, + {70196, 70196}, {70197, 70197}, {70198, 70199}, {70206, 70206}, + {70207, 70208}, {70209, 70209}, {70272, 70278}, {70280, 70280}, + {70282, 70285}, {70287, 70301}, {70303, 70312}, {70320, 70366}, + {70367, 70367}, {70368, 70370}, {70371, 70378}, {70384, 70393}, + {70400, 70401}, {70402, 70403}, {70405, 70412}, {70415, 70416}, + {70419, 70440}, {70442, 70448}, {70450, 70451}, {70453, 70457}, + {70459, 70460}, {70461, 70461}, {70462, 70463}, {70464, 70464}, + {70465, 70468}, {70471, 70472}, {70475, 70477}, {70480, 70480}, + {70487, 70487}, {70493, 70497}, {70498, 70499}, {70502, 70508}, + {70512, 70516}, {70656, 70708}, {70709, 70711}, {70712, 70719}, + {70720, 70721}, {70722, 70724}, {70725, 70725}, {70726, 70726}, + {70727, 70730}, {70736, 70745}, {70750, 70750}, {70751, 70753}, + {70784, 70831}, {70832, 70834}, {70835, 70840}, {70841, 70841}, + {70842, 70842}, {70843, 70846}, {70847, 70848}, {70849, 70849}, + {70850, 70851}, {70852, 70853}, {70855, 70855}, {70864, 70873}, + {71040, 71086}, {71087, 71089}, {71090, 71093}, {71096, 71099}, + {71100, 71101}, {71102, 71102}, {71103, 71104}, {71128, 71131}, + {71132, 71133}, {71168, 71215}, {71216, 71218}, {71219, 71226}, + {71227, 71228}, {71229, 71229}, {71230, 71230}, {71231, 71232}, + {71236, 71236}, {71248, 71257}, {71296, 71338}, {71339, 71339}, + {71340, 71340}, {71341, 71341}, {71342, 71343}, {71344, 71349}, + {71350, 71350}, {71351, 71351}, {71352, 71352}, {71360, 71369}, + {71424, 71450}, {71453, 71455}, {71456, 71457}, {71458, 71461}, + {71462, 71462}, {71463, 71467}, {71472, 71481}, {71488, 71494}, + {71680, 71723}, {71724, 71726}, {71727, 71735}, {71736, 71736}, + {71737, 71738}, {71840, 71903}, {71904, 71913}, {71935, 71942}, + {71945, 71945}, {71948, 71955}, {71957, 71958}, {71960, 71983}, + {71984, 71989}, {71991, 71992}, {71995, 71996}, {71997, 71997}, + {71998, 71998}, {71999, 71999}, {72000, 72000}, {72001, 72001}, + {72002, 72002}, {72003, 72003}, {72016, 72025}, {72096, 72103}, + {72106, 72144}, {72145, 72147}, {72148, 72151}, {72154, 72155}, + {72156, 72159}, {72160, 72160}, {72161, 72161}, {72163, 72163}, + {72164, 72164}, {72192, 72192}, {72193, 72202}, {72203, 72242}, + {72243, 72248}, {72249, 72249}, {72250, 72250}, {72251, 72254}, + {72263, 72263}, {72272, 72272}, {72273, 72278}, {72279, 72280}, + {72281, 72283}, {72284, 72329}, {72330, 72342}, {72343, 72343}, + {72344, 72345}, {72349, 72349}, {72368, 72440}, {72704, 72712}, + {72714, 72750}, {72751, 72751}, {72752, 72758}, {72760, 72765}, + {72766, 72766}, {72767, 72767}, {72768, 72768}, {72784, 72793}, + {72818, 72847}, {72850, 72871}, {72873, 72873}, {72874, 72880}, + {72881, 72881}, {72882, 72883}, {72884, 72884}, {72885, 72886}, + {72960, 72966}, {72968, 72969}, {72971, 73008}, {73009, 73014}, + {73018, 73018}, {73020, 73021}, {73023, 73029}, {73030, 73030}, + {73031, 73031}, {73040, 73049}, {73056, 73061}, {73063, 73064}, + {73066, 73097}, {73098, 73102}, {73104, 73105}, {73107, 73108}, + {73109, 73109}, {73110, 73110}, {73111, 73111}, {73112, 73112}, + {73120, 73129}, {73440, 73458}, {73459, 73460}, {73461, 73462}, + {73472, 73473}, {73474, 73474}, {73475, 73475}, {73476, 73488}, + {73490, 73523}, {73524, 73525}, {73526, 73530}, {73534, 73535}, + {73536, 73536}, {73537, 73537}, {73538, 73538}, {73552, 73561}, + {73648, 73648}, {73728, 74649}, {74752, 74862}, {74880, 75075}, + {77712, 77808}, {77824, 78895}, {78912, 78912}, {78913, 78918}, + {78919, 78933}, {82944, 83526}, {92160, 92728}, {92736, 92766}, + {92768, 92777}, {92784, 92862}, {92864, 92873}, {92880, 92909}, + {92912, 92916}, {92928, 92975}, {92976, 92982}, {92992, 92995}, + {93008, 93017}, {93027, 93047}, {93053, 93071}, {93760, 93823}, + {93952, 94026}, {94031, 94031}, {94032, 94032}, {94033, 94087}, + {94095, 94098}, {94099, 94111}, {94176, 94177}, {94179, 94179}, + {94180, 94180}, {94192, 94193}, {94208, 100343}, {100352, 101589}, + {101632, 101640}, {110576, 110579}, {110581, 110587}, {110589, 110590}, + {110592, 110882}, {110898, 110898}, {110928, 110930}, {110933, 110933}, + {110948, 110951}, {110960, 111355}, {113664, 113770}, {113776, 113788}, + {113792, 113800}, {113808, 113817}, {113821, 113822}, {118528, 118573}, + {118576, 118598}, {119141, 119142}, {119143, 119145}, {119149, 119154}, + {119163, 119170}, {119173, 119179}, {119210, 119213}, {119362, 119364}, + {119808, 119892}, {119894, 119964}, {119966, 119967}, {119970, 119970}, + {119973, 119974}, {119977, 119980}, {119982, 119993}, {119995, 119995}, + {119997, 120003}, {120005, 120069}, {120071, 120074}, {120077, 120084}, + {120086, 120092}, {120094, 120121}, {120123, 120126}, {120128, 120132}, + {120134, 120134}, {120138, 120144}, {120146, 120485}, {120488, 120512}, + {120514, 120538}, {120540, 120570}, {120572, 120596}, {120598, 120628}, + {120630, 120654}, {120656, 120686}, {120688, 120712}, {120714, 120744}, + {120746, 120770}, {120772, 120779}, {120782, 120831}, {121344, 121398}, + {121403, 121452}, {121461, 121461}, {121476, 121476}, {121499, 121503}, + {121505, 121519}, {122624, 122633}, {122634, 122634}, {122635, 122654}, + {122661, 122666}, {122880, 122886}, {122888, 122904}, {122907, 122913}, + {122915, 122916}, {122918, 122922}, {122928, 122989}, {123023, 123023}, + {123136, 123180}, {123184, 123190}, {123191, 123197}, {123200, 123209}, + {123214, 123214}, {123536, 123565}, {123566, 123566}, {123584, 123627}, + {123628, 123631}, {123632, 123641}, {124112, 124138}, {124139, 124139}, + {124140, 124143}, {124144, 124153}, {124896, 124902}, {124904, 124907}, + {124909, 124910}, {124912, 124926}, {124928, 125124}, {125136, 125142}, + {125184, 125251}, {125252, 125258}, {125259, 125259}, {125264, 125273}, + {126464, 126467}, {126469, 126495}, {126497, 126498}, {126500, 126500}, + {126503, 126503}, {126505, 126514}, {126516, 126519}, {126521, 126521}, + {126523, 126523}, {126530, 126530}, {126535, 126535}, {126537, 126537}, + {126539, 126539}, {126541, 126543}, {126545, 126546}, {126548, 126548}, + {126551, 126551}, {126553, 126553}, {126555, 126555}, {126557, 126557}, + {126559, 126559}, {126561, 126562}, {126564, 126564}, {126567, 126570}, + {126572, 126578}, {126580, 126583}, {126585, 126588}, {126590, 126590}, + {126592, 126601}, {126603, 126619}, {126625, 126627}, {126629, 126633}, + {126635, 126651}, {130032, 130041}, {131072, 173791}, {173824, 177977}, + {177984, 178205}, {178208, 183969}, {183984, 191456}, {191472, 192093}, + {194560, 195101}, {196608, 201546}, {201552, 205743}, {917760, 917999} +}; +const uint32_t id_start[740][2] = +{ + {65, 90}, {97, 122}, {170, 170}, {181, 181}, + {186, 186}, {192, 214}, {216, 246}, {248, 442}, + {443, 443}, {444, 447}, {448, 451}, {452, 659}, + {660, 660}, {661, 687}, {688, 705}, {710, 721}, + {736, 740}, {748, 748}, {750, 750}, {880, 883}, + {884, 884}, {886, 887}, {890, 890}, {891, 893}, + {895, 895}, {902, 902}, {904, 906}, {908, 908}, + {910, 929}, {931, 1013}, {1015, 1153}, {1162, 1327}, + {1329, 1366}, {1369, 1369}, {1376, 1416}, {1488, 1514}, + {1519, 1522}, {1568, 1599}, {1600, 1600}, {1601, 1610}, + {1646, 1647}, {1649, 1747}, {1749, 1749}, {1765, 1766}, + {1774, 1775}, {1786, 1788}, {1791, 1791}, {1808, 1808}, + {1810, 1839}, {1869, 1957}, {1969, 1969}, {1994, 2026}, + {2036, 2037}, {2042, 2042}, {2048, 2069}, {2074, 2074}, + {2084, 2084}, {2088, 2088}, {2112, 2136}, {2144, 2154}, + {2160, 2183}, {2185, 2190}, {2208, 2248}, {2249, 2249}, + {2308, 2361}, {2365, 2365}, {2384, 2384}, {2392, 2401}, + {2417, 2417}, {2418, 2432}, {2437, 2444}, {2447, 2448}, + {2451, 2472}, {2474, 2480}, {2482, 2482}, {2486, 2489}, + {2493, 2493}, {2510, 2510}, {2524, 2525}, {2527, 2529}, + {2544, 2545}, {2556, 2556}, {2565, 2570}, {2575, 2576}, + {2579, 2600}, {2602, 2608}, {2610, 2611}, {2613, 2614}, + {2616, 2617}, {2649, 2652}, {2654, 2654}, {2674, 2676}, + {2693, 2701}, {2703, 2705}, {2707, 2728}, {2730, 2736}, + {2738, 2739}, {2741, 2745}, {2749, 2749}, {2768, 2768}, + {2784, 2785}, {2809, 2809}, {2821, 2828}, {2831, 2832}, + {2835, 2856}, {2858, 2864}, {2866, 2867}, {2869, 2873}, + {2877, 2877}, {2908, 2909}, {2911, 2913}, {2929, 2929}, + {2947, 2947}, {2949, 2954}, {2958, 2960}, {2962, 2965}, + {2969, 2970}, {2972, 2972}, {2974, 2975}, {2979, 2980}, + {2984, 2986}, {2990, 3001}, {3024, 3024}, {3077, 3084}, + {3086, 3088}, {3090, 3112}, {3114, 3129}, {3133, 3133}, + {3160, 3162}, {3165, 3165}, {3168, 3169}, {3200, 3200}, + {3205, 3212}, {3214, 3216}, {3218, 3240}, {3242, 3251}, + {3253, 3257}, {3261, 3261}, {3293, 3294}, {3296, 3297}, + {3313, 3314}, {3332, 3340}, {3342, 3344}, {3346, 3386}, + {3389, 3389}, {3406, 3406}, {3412, 3414}, {3423, 3425}, + {3450, 3455}, {3461, 3478}, {3482, 3505}, {3507, 3515}, + {3517, 3517}, {3520, 3526}, {3585, 3632}, {3634, 3635}, + {3648, 3653}, {3654, 3654}, {3713, 3714}, {3716, 3716}, + {3718, 3722}, {3724, 3747}, {3749, 3749}, {3751, 3760}, + {3762, 3763}, {3773, 3773}, {3776, 3780}, {3782, 3782}, + {3804, 3807}, {3840, 3840}, {3904, 3911}, {3913, 3948}, + {3976, 3980}, {4096, 4138}, {4159, 4159}, {4176, 4181}, + {4186, 4189}, {4193, 4193}, {4197, 4198}, {4206, 4208}, + {4213, 4225}, {4238, 4238}, {4256, 4293}, {4295, 4295}, + {4301, 4301}, {4304, 4346}, {4348, 4348}, {4349, 4351}, + {4352, 4680}, {4682, 4685}, {4688, 4694}, {4696, 4696}, + {4698, 4701}, {4704, 4744}, {4746, 4749}, {4752, 4784}, + {4786, 4789}, {4792, 4798}, {4800, 4800}, {4802, 4805}, + {4808, 4822}, {4824, 4880}, {4882, 4885}, {4888, 4954}, + {4992, 5007}, {5024, 5109}, {5112, 5117}, {5121, 5740}, + {5743, 5759}, {5761, 5786}, {5792, 5866}, {5870, 5872}, + {5873, 5880}, {5888, 5905}, {5919, 5937}, {5952, 5969}, + {5984, 5996}, {5998, 6000}, {6016, 6067}, {6103, 6103}, + {6108, 6108}, {6176, 6210}, {6211, 6211}, {6212, 6264}, + {6272, 6276}, {6277, 6278}, {6279, 6312}, {6314, 6314}, + {6320, 6389}, {6400, 6430}, {6480, 6509}, {6512, 6516}, + {6528, 6571}, {6576, 6601}, {6656, 6678}, {6688, 6740}, + {6823, 6823}, {6917, 6963}, {6981, 6988}, {7043, 7072}, + {7086, 7087}, {7098, 7141}, {7168, 7203}, {7245, 7247}, + {7258, 7287}, {7288, 7293}, {7296, 7304}, {7312, 7354}, + {7357, 7359}, {7401, 7404}, {7406, 7411}, {7413, 7414}, + {7418, 7418}, {7424, 7467}, {7468, 7530}, {7531, 7543}, + {7544, 7544}, {7545, 7578}, {7579, 7615}, {7680, 7957}, + {7960, 7965}, {7968, 8005}, {8008, 8013}, {8016, 8023}, + {8025, 8025}, {8027, 8027}, {8029, 8029}, {8031, 8061}, + {8064, 8116}, {8118, 8124}, {8126, 8126}, {8130, 8132}, + {8134, 8140}, {8144, 8147}, {8150, 8155}, {8160, 8172}, + {8178, 8180}, {8182, 8188}, {8305, 8305}, {8319, 8319}, + {8336, 8348}, {8450, 8450}, {8455, 8455}, {8458, 8467}, + {8469, 8469}, {8472, 8472}, {8473, 8477}, {8484, 8484}, + {8486, 8486}, {8488, 8488}, {8490, 8493}, {8494, 8494}, + {8495, 8500}, {8501, 8504}, {8505, 8505}, {8508, 8511}, + {8517, 8521}, {8526, 8526}, {8544, 8578}, {8579, 8580}, + {8581, 8584}, {11264, 11387}, {11388, 11389}, {11390, 11492}, + {11499, 11502}, {11506, 11507}, {11520, 11557}, {11559, 11559}, + {11565, 11565}, {11568, 11623}, {11631, 11631}, {11648, 11670}, + {11680, 11686}, {11688, 11694}, {11696, 11702}, {11704, 11710}, + {11712, 11718}, {11720, 11726}, {11728, 11734}, {11736, 11742}, + {12293, 12293}, {12294, 12294}, {12295, 12295}, {12321, 12329}, + {12337, 12341}, {12344, 12346}, {12347, 12347}, {12348, 12348}, + {12353, 12438}, {12443, 12444}, {12445, 12446}, {12447, 12447}, + {12449, 12538}, {12540, 12542}, {12543, 12543}, {12549, 12591}, + {12593, 12686}, {12704, 12735}, {12784, 12799}, {13312, 19903}, + {19968, 40980}, {40981, 40981}, {40982, 42124}, {42192, 42231}, + {42232, 42237}, {42240, 42507}, {42508, 42508}, {42512, 42527}, + {42538, 42539}, {42560, 42605}, {42606, 42606}, {42623, 42623}, + {42624, 42651}, {42652, 42653}, {42656, 42725}, {42726, 42735}, + {42775, 42783}, {42786, 42863}, {42864, 42864}, {42865, 42887}, + {42888, 42888}, {42891, 42894}, {42895, 42895}, {42896, 42954}, + {42960, 42961}, {42963, 42963}, {42965, 42969}, {42994, 42996}, + {42997, 42998}, {42999, 42999}, {43000, 43001}, {43002, 43002}, + {43003, 43009}, {43011, 43013}, {43015, 43018}, {43020, 43042}, + {43072, 43123}, {43138, 43187}, {43250, 43255}, {43259, 43259}, + {43261, 43262}, {43274, 43301}, {43312, 43334}, {43360, 43388}, + {43396, 43442}, {43471, 43471}, {43488, 43492}, {43494, 43494}, + {43495, 43503}, {43514, 43518}, {43520, 43560}, {43584, 43586}, + {43588, 43595}, {43616, 43631}, {43632, 43632}, {43633, 43638}, + {43642, 43642}, {43646, 43695}, {43697, 43697}, {43701, 43702}, + {43705, 43709}, {43712, 43712}, {43714, 43714}, {43739, 43740}, + {43741, 43741}, {43744, 43754}, {43762, 43762}, {43763, 43764}, + {43777, 43782}, {43785, 43790}, {43793, 43798}, {43808, 43814}, + {43816, 43822}, {43824, 43866}, {43868, 43871}, {43872, 43880}, + {43881, 43881}, {43888, 43967}, {43968, 44002}, {44032, 55203}, + {55216, 55238}, {55243, 55291}, {63744, 64109}, {64112, 64217}, + {64256, 64262}, {64275, 64279}, {64285, 64285}, {64287, 64296}, + {64298, 64310}, {64312, 64316}, {64318, 64318}, {64320, 64321}, + {64323, 64324}, {64326, 64433}, {64467, 64829}, {64848, 64911}, + {64914, 64967}, {65008, 65019}, {65136, 65140}, {65142, 65276}, + {65313, 65338}, {65345, 65370}, {65382, 65391}, {65392, 65392}, + {65393, 65437}, {65438, 65439}, {65440, 65470}, {65474, 65479}, + {65482, 65487}, {65490, 65495}, {65498, 65500}, {65536, 65547}, + {65549, 65574}, {65576, 65594}, {65596, 65597}, {65599, 65613}, + {65616, 65629}, {65664, 65786}, {65856, 65908}, {66176, 66204}, + {66208, 66256}, {66304, 66335}, {66349, 66368}, {66369, 66369}, + {66370, 66377}, {66378, 66378}, {66384, 66421}, {66432, 66461}, + {66464, 66499}, {66504, 66511}, {66513, 66517}, {66560, 66639}, + {66640, 66717}, {66736, 66771}, {66776, 66811}, {66816, 66855}, + {66864, 66915}, {66928, 66938}, {66940, 66954}, {66956, 66962}, + {66964, 66965}, {66967, 66977}, {66979, 66993}, {66995, 67001}, + {67003, 67004}, {67072, 67382}, {67392, 67413}, {67424, 67431}, + {67456, 67461}, {67463, 67504}, {67506, 67514}, {67584, 67589}, + {67592, 67592}, {67594, 67637}, {67639, 67640}, {67644, 67644}, + {67647, 67669}, {67680, 67702}, {67712, 67742}, {67808, 67826}, + {67828, 67829}, {67840, 67861}, {67872, 67897}, {67968, 68023}, + {68030, 68031}, {68096, 68096}, {68112, 68115}, {68117, 68119}, + {68121, 68149}, {68192, 68220}, {68224, 68252}, {68288, 68295}, + {68297, 68324}, {68352, 68405}, {68416, 68437}, {68448, 68466}, + {68480, 68497}, {68608, 68680}, {68736, 68786}, {68800, 68850}, + {68864, 68899}, {69248, 69289}, {69296, 69297}, {69376, 69404}, + {69415, 69415}, {69424, 69445}, {69488, 69505}, {69552, 69572}, + {69600, 69622}, {69635, 69687}, {69745, 69746}, {69749, 69749}, + {69763, 69807}, {69840, 69864}, {69891, 69926}, {69956, 69956}, + {69959, 69959}, {69968, 70002}, {70006, 70006}, {70019, 70066}, + {70081, 70084}, {70106, 70106}, {70108, 70108}, {70144, 70161}, + {70163, 70187}, {70207, 70208}, {70272, 70278}, {70280, 70280}, + {70282, 70285}, {70287, 70301}, {70303, 70312}, {70320, 70366}, + {70405, 70412}, {70415, 70416}, {70419, 70440}, {70442, 70448}, + {70450, 70451}, {70453, 70457}, {70461, 70461}, {70480, 70480}, + {70493, 70497}, {70656, 70708}, {70727, 70730}, {70751, 70753}, + {70784, 70831}, {70852, 70853}, {70855, 70855}, {71040, 71086}, + {71128, 71131}, {71168, 71215}, {71236, 71236}, {71296, 71338}, + {71352, 71352}, {71424, 71450}, {71488, 71494}, {71680, 71723}, + {71840, 71903}, {71935, 71942}, {71945, 71945}, {71948, 71955}, + {71957, 71958}, {71960, 71983}, {71999, 71999}, {72001, 72001}, + {72096, 72103}, {72106, 72144}, {72161, 72161}, {72163, 72163}, + {72192, 72192}, {72203, 72242}, {72250, 72250}, {72272, 72272}, + {72284, 72329}, {72349, 72349}, {72368, 72440}, {72704, 72712}, + {72714, 72750}, {72768, 72768}, {72818, 72847}, {72960, 72966}, + {72968, 72969}, {72971, 73008}, {73030, 73030}, {73056, 73061}, + {73063, 73064}, {73066, 73097}, {73112, 73112}, {73440, 73458}, + {73474, 73474}, {73476, 73488}, {73490, 73523}, {73648, 73648}, + {73728, 74649}, {74752, 74862}, {74880, 75075}, {77712, 77808}, + {77824, 78895}, {78913, 78918}, {82944, 83526}, {92160, 92728}, + {92736, 92766}, {92784, 92862}, {92880, 92909}, {92928, 92975}, + {92992, 92995}, {93027, 93047}, {93053, 93071}, {93760, 93823}, + {93952, 94026}, {94032, 94032}, {94099, 94111}, {94176, 94177}, + {94179, 94179}, {94208, 100343}, {100352, 101589}, {101632, 101640}, + {110576, 110579}, {110581, 110587}, {110589, 110590}, {110592, 110882}, + {110898, 110898}, {110928, 110930}, {110933, 110933}, {110948, 110951}, + {110960, 111355}, {113664, 113770}, {113776, 113788}, {113792, 113800}, + {113808, 113817}, {119808, 119892}, {119894, 119964}, {119966, 119967}, + {119970, 119970}, {119973, 119974}, {119977, 119980}, {119982, 119993}, + {119995, 119995}, {119997, 120003}, {120005, 120069}, {120071, 120074}, + {120077, 120084}, {120086, 120092}, {120094, 120121}, {120123, 120126}, + {120128, 120132}, {120134, 120134}, {120138, 120144}, {120146, 120485}, + {120488, 120512}, {120514, 120538}, {120540, 120570}, {120572, 120596}, + {120598, 120628}, {120630, 120654}, {120656, 120686}, {120688, 120712}, + {120714, 120744}, {120746, 120770}, {120772, 120779}, {122624, 122633}, + {122634, 122634}, {122635, 122654}, {122661, 122666}, {122928, 122989}, + {123136, 123180}, {123191, 123197}, {123214, 123214}, {123536, 123565}, + {123584, 123627}, {124112, 124138}, {124139, 124139}, {124896, 124902}, + {124904, 124907}, {124909, 124910}, {124912, 124926}, {124928, 125124}, + {125184, 125251}, {125259, 125259}, {126464, 126467}, {126469, 126495}, + {126497, 126498}, {126500, 126500}, {126503, 126503}, {126505, 126514}, + {126516, 126519}, {126521, 126521}, {126523, 126523}, {126530, 126530}, + {126535, 126535}, {126537, 126537}, {126539, 126539}, {126541, 126543}, + {126545, 126546}, {126548, 126548}, {126551, 126551}, {126553, 126553}, + {126555, 126555}, {126557, 126557}, {126559, 126559}, {126561, 126562}, + {126564, 126564}, {126567, 126570}, {126572, 126578}, {126580, 126583}, + {126585, 126588}, {126590, 126590}, {126592, 126601}, {126603, 126619}, + {126625, 126627}, {126629, 126633}, {126635, 126651}, {131072, 173791}, + {173824, 177977}, {177984, 178205}, {178208, 183969}, {183984, 191456}, + {191472, 192093}, {194560, 195101}, {196608, 201546}, {201552, 205743} +}; + + +} // namespace ada::idna +#endif // ADA_IDNA_IDENTIFIER_TABLES_H + +/* end file src/id_tables.cpp */ + +namespace ada::idna { +// return 0xffffffff in case of error +// We do not fully validate the input +uint32_t get_first_code_point(std::string_view input) { + constexpr uint32_t error = 0xffffffff; + // Check if the input is empty + if (input.empty()) { + return error; + } + + uint32_t code_point = 0; + size_t number_bytes = 0; + unsigned char first_byte = input[0]; + + if ((first_byte & 0x80) == 0) { + // 1-byte character (ASCII) + return first_byte; + } else if ((first_byte & 0xE0) == 0xC0) { + // 2-byte character + code_point = first_byte & 0x1F; + number_bytes = 2; + } else if ((first_byte & 0xF0) == 0xE0) { + // 3-byte character + code_point = first_byte & 0x0F; + number_bytes = 3; + } else if ((first_byte & 0xF8) == 0xF0) { + // 4-byte character + code_point = first_byte & 0x07; + number_bytes = 4; + } else { + return error; + } + + // Decode the remaining bytes + for (size_t i = 1; i < number_bytes; ++i) { + if (i >= input.size()) { + return error; + } + unsigned char byte = input[i]; + if ((byte & 0xC0) != 0x80) { + return error; + } + code_point = (code_point << 6) | (byte & 0x3F); + } + return code_point; +} + +bool is_ascii_letter(char32_t c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +bool is_ascii_letter_or_digit(char32_t c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9'); +} + +bool valid_name_code_point(char32_t code_point, bool first) { + // https://tc39.es/ecma262/#prod-IdentifierStart + // Fast paths: + if (first && + (code_point == '$' || code_point == '_' || is_ascii_letter(code_point))) { + return true; + } + if (!first && (code_point == '$' || is_ascii_letter_or_digit(code_point))) { + return true; + } + // Slow path... + if (code_point == 0xffffffff) { + return false; // minimal error handling + } + if (first) { + auto iter = std::lower_bound( + std::begin(ada::idna::id_start), std::end(ada::idna::id_start), + code_point, [](const uint32_t* range, uint32_t code_point) { + return range[1] < code_point; + }); + return iter != std::end(id_start) && code_point >= (*iter)[0]; + } else { + auto iter = std::lower_bound( + std::begin(id_continue), std::end(id_continue), code_point, + [](const uint32_t* range, uint32_t code_point) { + return range[1] < code_point; + }); + return iter != std::end(id_start) && code_point >= (*iter)[0]; + } +} +} // namespace ada::idna +/* end file src/identifier.cpp */ +/* end file src/idna.cpp */ +/* end file src/ada_idna.cpp */ +ADA_POP_DISABLE_WARNINGS + +#include +#if ADA_NEON +#include +#elif ADA_SSE2 +#include +#endif + +namespace ada::unicode { + +constexpr bool is_tabs_or_newline(char c) noexcept { + return c == '\r' || c == '\n' || c == '\t'; +} + +constexpr uint64_t broadcast(uint8_t v) noexcept { + return 0x101010101010101ull * v; +} + +constexpr bool to_lower_ascii(char* input, size_t length) noexcept { + uint64_t broadcast_80 = broadcast(0x80); + uint64_t broadcast_Ap = broadcast(128 - 'A'); + uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1); + uint64_t non_ascii = 0; + size_t i = 0; + + for (; i + 7 < length; i += 8) { + uint64_t word{}; + memcpy(&word, input + i, sizeof(word)); + non_ascii |= (word & broadcast_80); + word ^= + (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; + memcpy(input + i, &word, sizeof(word)); + } + if (i < length) { + uint64_t word{}; + memcpy(&word, input + i, length - i); + non_ascii |= (word & broadcast_80); + word ^= + (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2; + memcpy(input + i, &word, length - i); + } + return non_ascii == 0; +} +#if ADA_NEON +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + // first check for short strings in which case we do it naively. + if (user_input.size() < 16) { // slow path + return std::any_of(user_input.begin(), user_input.end(), + is_tabs_or_newline); + } + // fast path for long strings (expected to be common) + size_t i = 0; + /** + * The fastest way to check for `\t` (==9), '\n'(== 10) and `\r` (==13) relies + * on table lookup instruction. We notice that these are all unique numbers + * between 0..15. Let's prepare a special register, where we put '\t' in the + * 9th position, '\n' - 10th and '\r' - 13th. Then we shuffle this register by + * input register. If the input had `\t` in position X then this shuffled + * register will also have '\t' in that position. Comparing input with this + * shuffled register will mark us all interesting characters in the input. + * + * credit for algorithmic idea: @aqrit, credit for description: + * @DenisYaroshevskiy + */ + static uint8_t rnt_array[16] = {1, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 10, 0, 0, 13, 0, 0}; + const uint8x16_t rnt = vld1q_u8(rnt_array); + // m['0xd', '0xa', '0x9'] + uint8x16_t running{0}; + for (; i + 15 < user_input.size(); i += 16) { + uint8x16_t word = vld1q_u8((const uint8_t*)user_input.data() + i); + + running = vorrq_u8(running, vceqq_u8(vqtbl1q_u8(rnt, word), word)); + } + if (i < user_input.size()) { + uint8x16_t word = + vld1q_u8((const uint8_t*)user_input.data() + user_input.length() - 16); + running = vorrq_u8(running, vceqq_u8(vqtbl1q_u8(rnt, word), word)); + } + return vmaxvq_u32(vreinterpretq_u32_u8(running)) != 0; +} +#elif ADA_SSE2 +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + // first check for short strings in which case we do it naively. + if (user_input.size() < 16) { // slow path + return std::any_of(user_input.begin(), user_input.end(), + is_tabs_or_newline); + } + // fast path for long strings (expected to be common) + size_t i = 0; + const __m128i mask1 = _mm_set1_epi8('\r'); + const __m128i mask2 = _mm_set1_epi8('\n'); + const __m128i mask3 = _mm_set1_epi8('\t'); + // If we supported SSSE3, we could use the algorithm that we use for NEON. + __m128i running{0}; + for (; i + 15 < user_input.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i)); + running = _mm_or_si128( + _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1), + _mm_cmpeq_epi8(word, mask2))), + _mm_cmpeq_epi8(word, mask3)); + } + if (i < user_input.size()) { + __m128i word = _mm_loadu_si128( + (const __m128i*)(user_input.data() + user_input.length() - 16)); + running = _mm_or_si128( + _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1), + _mm_cmpeq_epi8(word, mask2))), + _mm_cmpeq_epi8(word, mask3)); + } + return _mm_movemask_epi8(running) != 0; +} +#else +ada_really_inline bool has_tabs_or_newline( + std::string_view user_input) noexcept { + auto has_zero_byte = [](uint64_t v) { + return ((v - 0x0101010101010101) & ~(v) & 0x8080808080808080); + }; + size_t i = 0; + uint64_t mask1 = broadcast('\r'); + uint64_t mask2 = broadcast('\n'); + uint64_t mask3 = broadcast('\t'); + uint64_t running{0}; + for (; i + 7 < user_input.size(); i += 8) { + uint64_t word{}; + memcpy(&word, user_input.data() + i, sizeof(word)); + uint64_t xor1 = word ^ mask1; + uint64_t xor2 = word ^ mask2; + uint64_t xor3 = word ^ mask3; + running |= has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3); + } + if (i < user_input.size()) { + uint64_t word{}; + memcpy(&word, user_input.data() + i, user_input.size() - i); + uint64_t xor1 = word ^ mask1; + uint64_t xor2 = word ^ mask2; + uint64_t xor3 = word ^ mask3; + running |= has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3); + } + return running; +} +#endif + +// A forbidden host code point is U+0000 NULL, U+0009 TAB, U+000A LF, U+000D CR, +// U+0020 SPACE, U+0023 (#), U+002F (/), U+003A (:), U+003C (<), U+003E (>), +// U+003F (?), U+0040 (@), U+005B ([), U+005C (\), U+005D (]), U+005E (^), or +// U+007C (|). +constexpr static std::array is_forbidden_host_code_point_table = + []() consteval { + std::array result{}; + for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', + '>', '?', '@', '[', '\\', ']', '^', '|'}) { + result[c] = true; + } + return result; + }(); + +ada_really_inline constexpr bool is_forbidden_host_code_point( + const char c) noexcept { + return is_forbidden_host_code_point_table[uint8_t(c)]; +} + +constexpr static std::array is_forbidden_domain_code_point_table = + []() consteval { + std::array result{}; + for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', + '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { + result[c] = true; + } + for (uint8_t c = 0; c <= 32; c++) { + result[c] = true; + } + for (size_t c = 127; c < 255; c++) { + result[c] = true; + } + return result; + }(); + +static_assert(sizeof(is_forbidden_domain_code_point_table) == 256); + +ada_really_inline constexpr bool is_forbidden_domain_code_point( + const char c) noexcept { + return is_forbidden_domain_code_point_table[uint8_t(c)]; +} + +ada_really_inline constexpr bool contains_forbidden_domain_code_point( + const char* input, size_t length) noexcept { + size_t i = 0; + uint8_t accumulator{}; + for (; i + 4 <= length; i += 4) { + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])]; + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])]; + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])]; + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])]; + } + for (; i < length; i++) { + accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])]; + } + return accumulator; +} + +constexpr static std::array + is_forbidden_domain_code_point_table_or_upper = []() consteval { + std::array result{}; + for (uint8_t c : {'\0', '\x09', '\x0a', '\x0d', ' ', '#', '/', ':', '<', + '>', '?', '@', '[', '\\', ']', '^', '|', '%'}) { + result[c] = 1; + } + for (uint8_t c = 'A'; c <= 'Z'; c++) { + result[c] = 2; + } + for (uint8_t c = 0; c <= 32; c++) { + result[c] = 1; + } + for (size_t c = 127; c < 255; c++) { + result[c] = 1; + } + return result; + }(); + +ada_really_inline constexpr uint8_t +contains_forbidden_domain_code_point_or_upper(const char* input, + size_t length) noexcept { + size_t i = 0; + uint8_t accumulator{}; + for (; i + 4 <= length; i += 4) { + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])]; + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])]; + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])]; + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])]; + } + for (; i < length; i++) { + accumulator |= + is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])]; + } + return accumulator; +} + +// std::isalnum(c) || c == '+' || c == '-' || c == '.') is true for +constexpr static std::array is_alnum_plus_table = []() consteval { + std::array result{}; + for (size_t c = 0; c < 256; c++) { + result[c] = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || c == '+' || c == '-' || c == '.'; + } + return result; +}(); + +ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept { + return is_alnum_plus_table[uint8_t(c)]; + // A table is almost surely much faster than the + // following under most compilers: return + // return (std::isalnum(c) || c == '+' || c == '-' || c == '.'); +} + +ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f'); +} + +ada_really_inline constexpr bool is_ascii_digit(const char c) noexcept { + // An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9), + // inclusive. + return (c >= '0' && c <= '9'); +} + +ada_really_inline constexpr bool is_ascii(const char32_t c) noexcept { + // If code point is between U+0000 and U+007F inclusive, then return true. + return c <= 0x7F; +} + +ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept { + return (unsigned char)c <= ' '; +} + +ada_really_inline constexpr bool is_ascii_tab_or_newline( + const char c) noexcept { + return c == '\t' || c == '\n' || c == '\r'; +} + +constexpr std::string_view table_is_double_dot_path_segment[] = { + "..", "%2e.", ".%2e", "%2e%2e"}; + +ada_really_inline constexpr bool is_double_dot_path_segment( + std::string_view input) noexcept { + // This will catch most cases: + // The length must be 2,4 or 6. + // We divide by two and require + // that the result be between 1 and 3 inclusively. + uint64_t half_length = uint64_t(input.size()) / 2; + if (half_length - 1 > 2) { + return false; + } + // We have a string of length 2, 4 or 6. + // We now check the first character: + if ((input[0] != '.') && (input[0] != '%')) { + return false; + } + // We are unlikely the get beyond this point. + int hash_value = (input.size() + (unsigned)(input[0])) & 3; + const std::string_view target = table_is_double_dot_path_segment[hash_value]; + if (target.size() != input.size()) { + return false; + } + // We almost never get here. + // Optimizing the rest is relatively unimportant. + auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) { + uint16_t A, B; + memcpy(&A, a.data(), sizeof(A)); + memcpy(&B, b.data(), sizeof(B)); + return A == B; + }; + if (!prefix_equal_unsafe(input, target)) { + return false; + } + for (size_t i = 2; i < input.size(); i++) { + char c = input[i]; + if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) { + return false; + } + } + return true; + // The above code might be a bit better than the code below. Compilers + // are not stupid and may use the fact that these strings have length 2,4 and + // 6 and other tricks. + // return input == ".." || + // input == ".%2e" || input == ".%2E" || + // input == "%2e." || input == "%2E." || + // input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input == + // "%2e%2E"; +} + +ada_really_inline constexpr bool is_single_dot_path_segment( + std::string_view input) noexcept { + return input == "." || input == "%2e" || input == "%2E"; +} + +ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); +} + +constexpr static char hex_to_binary_table[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, + 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15}; +unsigned constexpr convert_hex_to_binary(const char c) noexcept { + return hex_to_binary_table[c - '0']; +} + +std::string percent_decode(const std::string_view input, size_t first_percent) { + // next line is for safety only, we expect users to avoid calling + // percent_decode when first_percent is outside the range. + if (first_percent == std::string_view::npos) { + return std::string(input); + } + std::string dest; + dest.reserve(input.length()); + dest.append(input.substr(0, first_percent)); + const char* pointer = input.data() + first_percent; + const char* end = input.data() + input.size(); + // Optimization opportunity: if the following code gets + // called often, it can be optimized quite a bit. + while (pointer < end) { + const char ch = pointer[0]; + size_t remaining = end - pointer - 1; + if (ch != '%' || remaining < 2 || + ( // ch == '%' && // It is unnecessary to check that ch == '%'. + (!is_ascii_hex_digit(pointer[1]) || + !is_ascii_hex_digit(pointer[2])))) { + dest += ch; + pointer++; + } else { + unsigned a = convert_hex_to_binary(pointer[1]); + unsigned b = convert_hex_to_binary(pointer[2]); + char c = static_cast(a * 16 + b); + dest += c; + pointer += 3; + } + } + return dest; +} + +std::string percent_encode(const std::string_view input, + const uint8_t character_set[]) { + auto pointer = std::ranges::find_if(input, [character_set](const char c) { + return character_sets::bit_at(character_set, c); + }); + // Optimization: Don't iterate if percent encode is not required + if (pointer == input.end()) { + return std::string(input); + } + + std::string result; + result.reserve(input.length()); // in the worst case, percent encoding might + // produce 3 characters. + result.append(input.substr(0, std::distance(input.begin(), pointer))); + + for (; pointer != input.end(); pointer++) { + if (character_sets::bit_at(character_set, *pointer)) { + result.append(character_sets::hex + uint8_t(*pointer) * 4, 3); + } else { + result += *pointer; + } + } + + return result; +} + +template +bool percent_encode(const std::string_view input, const uint8_t character_set[], + std::string& out) { + ada_log("percent_encode ", input, " to output string while ", + append ? "appending" : "overwriting"); + auto pointer = + std::find_if(input.begin(), input.end(), [character_set](const char c) { + return character_sets::bit_at(character_set, c); + }); + ada_log("percent_encode done checking, moved to ", + std::distance(input.begin(), pointer)); + + // Optimization: Don't iterate if percent encode is not required + if (pointer == input.end()) { + ada_log("percent_encode encoding not needed."); + return false; + } + if constexpr (!append) { + out.clear(); + } + ada_log("percent_encode appending ", std::distance(input.begin(), pointer), + " bytes"); + out.append(input.data(), std::distance(input.begin(), pointer)); + ada_log("percent_encode processing ", std::distance(pointer, input.end()), + " bytes"); + for (; pointer != input.end(); pointer++) { + if (character_sets::bit_at(character_set, *pointer)) { + out.append(character_sets::hex + uint8_t(*pointer) * 4, 3); + } else { + out += *pointer; + } + } + return true; +} + +bool to_ascii(std::optional& out, const std::string_view plain, + size_t first_percent) { + std::string percent_decoded_buffer; + std::string_view input = plain; + if (first_percent != std::string_view::npos) { + percent_decoded_buffer = unicode::percent_decode(plain, first_percent); + input = percent_decoded_buffer; + } + // input is a non-empty UTF-8 string, must be percent decoded + std::string idna_ascii = ada::idna::to_ascii(input); + if (idna_ascii.empty() || contains_forbidden_domain_code_point( + idna_ascii.data(), idna_ascii.size())) { + return false; + } + out = std::move(idna_ascii); + return true; +} + +std::string percent_encode(const std::string_view input, + const uint8_t character_set[], size_t index) { + std::string out; + out.append(input.data(), index); + auto pointer = input.begin() + index; + for (; pointer != input.end(); pointer++) { + if (character_sets::bit_at(character_set, *pointer)) { + out.append(character_sets::hex + uint8_t(*pointer) * 4, 3); + } else { + out += *pointer; + } + } + return out; +} + +} // namespace ada::unicode +/* end file src/unicode.cpp */ +/* begin file src/serializers.cpp */ +#include +#include +#include + +namespace ada::serializers { + +void find_longest_sequence_of_ipv6_pieces( + const std::array& address, size_t& compress, + size_t& compress_length) noexcept { + for (size_t i = 0; i < 8; i++) { + if (address[i] == 0) { + size_t next = i + 1; + while (next != 8 && address[next] == 0) ++next; + const size_t count = next - i; + if (compress_length < count) { + compress_length = count; + compress = i; + if (next == 8) break; + i = next; + } + } + } +} + +std::string ipv6(const std::array& address) noexcept { + size_t compress_length = 0; // The length of a long sequence of zeros. + size_t compress = 0; // The start of a long sequence of zeros. + find_longest_sequence_of_ipv6_pieces(address, compress, compress_length); + + if (compress_length <= 1) { + // Optimization opportunity: Find a faster way then snprintf for imploding + // and return here. + compress = compress_length = 8; + } + + std::string output(4 * 8 + 7 + 2, '\0'); + size_t piece_index = 0; + char* point = output.data(); + char* point_end = output.data() + output.size(); + *point++ = '['; + while (true) { + if (piece_index == compress) { + *point++ = ':'; + // If we skip a value initially, we need to write '::', otherwise + // a single ':' will do since it follows a previous ':'. + if (piece_index == 0) { + *point++ = ':'; + } + piece_index += compress_length; + if (piece_index == 8) { + break; + } + } + point = std::to_chars(point, point_end, address[piece_index], 16).ptr; + piece_index++; + if (piece_index == 8) { + break; + } + *point++ = ':'; + } + *point++ = ']'; + output.resize(point - output.data()); + return output; +} + +std::string ipv4(const uint64_t address) noexcept { + std::string output(15, '\0'); + char* point = output.data(); + char* point_end = output.data() + output.size(); + point = std::to_chars(point, point_end, uint8_t(address >> 24)).ptr; + for (int i = 2; i >= 0; i--) { + *point++ = '.'; + point = std::to_chars(point, point_end, uint8_t(address >> (i * 8))).ptr; + } + output.resize(point - output.data()); + return output; +} + +} // namespace ada::serializers +/* end file src/serializers.cpp */ +/* begin file src/implementation.cpp */ + +#include + + +namespace ada { + +template +ada_warn_unused tl::expected parse( + std::string_view input, const result_type* base_url) { + result_type u = + ada::parser::parse_url_impl(input, base_url); + if (!u.is_valid) { + return tl::unexpected(errors::type_error); + } + return u; +} + +template ada::result parse(std::string_view input, + const url* base_url = nullptr); +template ada::result parse( + std::string_view input, const url_aggregator* base_url = nullptr); + +std::string href_from_file(std::string_view input) { + // This is going to be much faster than constructing a URL. + std::string tmp_buffer; + std::string_view internal_input; + if (unicode::has_tabs_or_newline(input)) { + tmp_buffer = input; + helpers::remove_ascii_tab_or_newline(tmp_buffer); + internal_input = tmp_buffer; + } else { + internal_input = input; + } + std::string path; + if (internal_input.empty()) { + path = "/"; + } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { + helpers::parse_prepared_path(internal_input.substr(1), + ada::scheme::type::FILE, path); + } else { + helpers::parse_prepared_path(internal_input, ada::scheme::type::FILE, path); + } + return "file://" + path; +} + +bool can_parse(std::string_view input, const std::string_view* base_input) { + ada::url_aggregator base_aggregator; + ada::url_aggregator* base_pointer = nullptr; + + if (base_input != nullptr) { + base_aggregator = ada::parser::parse_url_impl( + *base_input, nullptr); + if (!base_aggregator.is_valid) { + return false; + } + base_pointer = &base_aggregator; + } + + ada::url_aggregator result = + ada::parser::parse_url_impl(input, + base_pointer); + return result.is_valid; +} + +ada_warn_unused std::string to_string(ada::encoding_type type) { + switch (type) { + case ada::encoding_type::UTF8: + return "UTF-8"; + case ada::encoding_type::UTF_16LE: + return "UTF-16LE"; + case ada::encoding_type::UTF_16BE: + return "UTF-16BE"; + default: + unreachable(); + } +} + +} // namespace ada +/* end file src/implementation.cpp */ +/* begin file src/helpers.cpp */ + +#include +#include + +namespace ada::helpers { + +template +void encode_json(std::string_view view, out_iter out) { + // trivial implementation. could be faster. + const char* hexvalues = + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; + for (uint8_t c : view) { + if (c == '\\') { + *out++ = '\\'; + *out++ = '\\'; + } else if (c == '"') { + *out++ = '\\'; + *out++ = '"'; + } else if (c <= 0x1f) { + *out++ = '\\'; + *out++ = 'u'; + *out++ = '0'; + *out++ = '0'; + *out++ = hexvalues[2 * c]; + *out++ = hexvalues[2 * c + 1]; + } else { + *out++ = c; + } + } +} + +ada_unused std::string get_state(ada::state s) { + switch (s) { + case ada::state::AUTHORITY: + return "Authority"; + case ada::state::SCHEME_START: + return "Scheme Start"; + case ada::state::SCHEME: + return "Scheme"; + case ada::state::HOST: + return "Host"; + case ada::state::NO_SCHEME: + return "No Scheme"; + case ada::state::FRAGMENT: + return "Fragment"; + case ada::state::RELATIVE_SCHEME: + return "Relative Scheme"; + case ada::state::RELATIVE_SLASH: + return "Relative Slash"; + case ada::state::FILE: + return "File"; + case ada::state::FILE_HOST: + return "File Host"; + case ada::state::FILE_SLASH: + return "File Slash"; + case ada::state::PATH_OR_AUTHORITY: + return "Path or Authority"; + case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES: + return "Special Authority Ignore Slashes"; + case ada::state::SPECIAL_AUTHORITY_SLASHES: + return "Special Authority Slashes"; + case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY: + return "Special Relative or Authority"; + case ada::state::QUERY: + return "Query"; + case ada::state::PATH: + return "Path"; + case ada::state::PATH_START: + return "Path Start"; + case ada::state::OPAQUE_PATH: + return "Opaque Path"; + case ada::state::PORT: + return "Port"; + default: + return "unknown state"; + } +} + +ada_really_inline std::optional prune_hash( + std::string_view& input) noexcept { + // compiles down to 20--30 instructions including a class to memchr (C + // function). this function should be quite fast. + size_t location_of_first = input.find('#'); + if (location_of_first == std::string_view::npos) { + return std::nullopt; + } + std::string_view hash = input; + hash.remove_prefix(location_of_first + 1); + input.remove_suffix(input.size() - location_of_first); + return hash; +} + +ada_really_inline bool shorten_path(std::string& path, + ada::scheme::type type) noexcept { + // Let path be url's path. + // If url's scheme is "file", path's size is 1, and path[0] is a normalized + // Windows drive letter, then return. + if (type == ada::scheme::type::FILE && + path.find('/', 1) == std::string_view::npos && !path.empty()) { + if (checkers::is_normalized_windows_drive_letter( + helpers::substring(path, 1))) { + return false; + } + } + + // Remove path's last item, if any. + size_t last_delimiter = path.rfind('/'); + if (last_delimiter != std::string::npos) { + path.erase(last_delimiter); + return true; + } + + return false; +} + +ada_really_inline bool shorten_path(std::string_view& path, + ada::scheme::type type) noexcept { + // Let path be url's path. + // If url's scheme is "file", path's size is 1, and path[0] is a normalized + // Windows drive letter, then return. + if (type == ada::scheme::type::FILE && + path.find('/', 1) == std::string_view::npos && !path.empty()) { + if (checkers::is_normalized_windows_drive_letter( + helpers::substring(path, 1))) { + return false; + } + } + + // Remove path's last item, if any. + if (!path.empty()) { + size_t slash_loc = path.rfind('/'); + if (slash_loc != std::string_view::npos) { + path.remove_suffix(path.size() - slash_loc); + return true; + } + } + + return false; +} + +ada_really_inline void remove_ascii_tab_or_newline( + std::string& input) noexcept { + // if this ever becomes a performance issue, we could use an approach similar + // to has_tabs_or_newline + std::erase_if(input, ada::unicode::is_ascii_tab_or_newline); +} + +ada_really_inline constexpr std::string_view substring(std::string_view input, + size_t pos) noexcept { + ADA_ASSERT_TRUE(pos <= input.size()); + // The following is safer but unneeded if we have the above line: + // return pos > input.size() ? std::string_view() : input.substr(pos); + return input.substr(pos); +} + +ada_really_inline void resize(std::string_view& input, size_t pos) noexcept { + ADA_ASSERT_TRUE(pos <= input.size()); + input.remove_suffix(input.size() - pos); +} + +// computes the number of trailing zeroes +// this is a private inline function only defined in this source file. +ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept { +#ifdef ADA_REGULAR_VISUAL_STUDIO + unsigned long ret; + // Search the mask data from least significant bit (LSB) + // to the most significant bit (MSB) for a set bit (1). + _BitScanForward(&ret, input_num); + return (int)ret; +#else // ADA_REGULAR_VISUAL_STUDIO + return __builtin_ctzl(input_num); +#endif // ADA_REGULAR_VISUAL_STUDIO +} + +// starting at index location, this finds the next location of a character +// :, /, \\, ? or [. If none is found, view.size() is returned. +// For use within get_host_delimiter_location. +#if ADA_NEON +// The ada_make_uint8x16_t macro is necessary because Visual Studio does not +// support direct initialization of uint8x16_t. See +// https://developercommunity.visualstudio.com/t/error-C2078:-too-many-initializers-whe/402911?q=backend+neon +#ifndef ada_make_uint8x16_t +#define ada_make_uint8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \ + x13, x14, x15, x16) \ + ([=]() { \ + static uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \ + x9, x10, x11, x12, x13, x14, x15, x16}; \ + return vld1q_u8(array); \ + }()) +#endif + +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || + view[i] == '?' || view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + auto to_bitmask = [](uint8x16_t input) -> uint16_t { + uint8x16_t bit_mask = + ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01, + 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); + uint8x16_t minput = vandq_u8(input, bit_mask); + uint8x16_t tmp = vpaddq_u8(minput, minput); + tmp = vpaddq_u8(tmp, tmp); + tmp = vpaddq_u8(tmp, tmp); + return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0); + }; + + // fast path for long strings (expected to be common) + size_t i = location; + uint8x16_t low_mask = + ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x03); + uint8x16_t high_mask = + ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + uint8x16_t fmask = vmovq_n_u8(0xf); + uint8x16_t zero{0}; + for (; i + 15 < view.size(); i += 16) { + uint8x16_t word = vld1q_u8((const uint8_t*)view.data() + i); + uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); + uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); + uint8x16_t classify = vandq_u8(lowpart, highpart); + if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) { + uint8x16_t is_zero = vceqq_u8(classify, zero); + uint16_t is_non_zero = ~to_bitmask(is_zero); + return i + trailing_zeroes(is_non_zero); + } + } + + if (i < view.size()) { + uint8x16_t word = + vld1q_u8((const uint8_t*)view.data() + view.length() - 16); + uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); + uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); + uint8x16_t classify = vandq_u8(lowpart, highpart); + if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) { + uint8x16_t is_zero = vceqq_u8(classify, zero); + uint16_t is_non_zero = ~to_bitmask(is_zero); + return view.length() - 16 + trailing_zeroes(is_non_zero); + } + } + return size_t(view.size()); +} +#elif ADA_SSE2 +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '\\' || + view[i] == '?' || view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + // fast path for long strings (expected to be common) + size_t i = location; + const __m128i mask1 = _mm_set1_epi8(':'); + const __m128i mask2 = _mm_set1_epi8('/'); + const __m128i mask3 = _mm_set1_epi8('\\'); + const __m128i mask4 = _mm_set1_epi8('?'); + const __m128i mask5 = _mm_set1_epi8('['); + + for (; i + 15 < view.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); + __m128i m1 = _mm_cmpeq_epi8(word, mask1); + __m128i m2 = _mm_cmpeq_epi8(word, mask2); + __m128i m3 = _mm_cmpeq_epi8(word, mask3); + __m128i m4 = _mm_cmpeq_epi8(word, mask4); + __m128i m5 = _mm_cmpeq_epi8(word, mask5); + __m128i m = _mm_or_si128( + _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5); + int mask = _mm_movemask_epi8(m); + if (mask != 0) { + return i + trailing_zeroes(mask); + } + } + if (i < view.size()) { + __m128i word = + _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); + __m128i m1 = _mm_cmpeq_epi8(word, mask1); + __m128i m2 = _mm_cmpeq_epi8(word, mask2); + __m128i m3 = _mm_cmpeq_epi8(word, mask3); + __m128i m4 = _mm_cmpeq_epi8(word, mask4); + __m128i m5 = _mm_cmpeq_epi8(word, mask5); + __m128i m = _mm_or_si128( + _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5); + int mask = _mm_movemask_epi8(m); + if (mask != 0) { + return view.length() - 16 + trailing_zeroes(mask); + } + } + return size_t(view.length()); +} +#else +// : / [ \\ ? +static constexpr std::array special_host_delimiters = + []() consteval { + std::array result{}; + for (int i : {':', '/', '[', '\\', '?'}) { + result[i] = 1; + } + return result; + }(); +// credit: @the-moisrex recommended a table-based approach +ada_really_inline size_t find_next_host_delimiter_special( + std::string_view view, size_t location) noexcept { + auto const str = view.substr(location); + for (auto pos = str.begin(); pos != str.end(); ++pos) { + if (special_host_delimiters[(uint8_t)*pos]) { + return pos - str.begin() + location; + } + } + return size_t(view.size()); +} +#endif + +// starting at index location, this finds the next location of a character +// :, /, ? or [. If none is found, view.size() is returned. +// For use within get_host_delimiter_location. +#if ADA_NEON +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '?' || + view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + auto to_bitmask = [](uint8x16_t input) -> uint16_t { + uint8x16_t bit_mask = + ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01, + 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); + uint8x16_t minput = vandq_u8(input, bit_mask); + uint8x16_t tmp = vpaddq_u8(minput, minput); + tmp = vpaddq_u8(tmp, tmp); + tmp = vpaddq_u8(tmp, tmp); + return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0); + }; + + // fast path for long strings (expected to be common) + size_t i = location; + uint8x16_t low_mask = + ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x03); + uint8x16_t high_mask = + ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + uint8x16_t fmask = vmovq_n_u8(0xf); + uint8x16_t zero{0}; + for (; i + 15 < view.size(); i += 16) { + uint8x16_t word = vld1q_u8((const uint8_t*)view.data() + i); + uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); + uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); + uint8x16_t classify = vandq_u8(lowpart, highpart); + if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) { + uint8x16_t is_zero = vceqq_u8(classify, zero); + uint16_t is_non_zero = ~to_bitmask(is_zero); + return i + trailing_zeroes(is_non_zero); + } + } + + if (i < view.size()) { + uint8x16_t word = + vld1q_u8((const uint8_t*)view.data() + view.length() - 16); + uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask)); + uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4)); + uint8x16_t classify = vandq_u8(lowpart, highpart); + if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) { + uint8x16_t is_zero = vceqq_u8(classify, zero); + uint16_t is_non_zero = ~to_bitmask(is_zero); + return view.length() - 16 + trailing_zeroes(is_non_zero); + } + } + return size_t(view.size()); +} +#elif ADA_SSE2 +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + // first check for short strings in which case we do it naively. + if (view.size() - location < 16) { // slow path + for (size_t i = location; i < view.size(); i++) { + if (view[i] == ':' || view[i] == '/' || view[i] == '?' || + view[i] == '[') { + return i; + } + } + return size_t(view.size()); + } + // fast path for long strings (expected to be common) + size_t i = location; + const __m128i mask1 = _mm_set1_epi8(':'); + const __m128i mask2 = _mm_set1_epi8('/'); + const __m128i mask4 = _mm_set1_epi8('?'); + const __m128i mask5 = _mm_set1_epi8('['); + + for (; i + 15 < view.size(); i += 16) { + __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i)); + __m128i m1 = _mm_cmpeq_epi8(word, mask1); + __m128i m2 = _mm_cmpeq_epi8(word, mask2); + __m128i m4 = _mm_cmpeq_epi8(word, mask4); + __m128i m5 = _mm_cmpeq_epi8(word, mask5); + __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5)); + int mask = _mm_movemask_epi8(m); + if (mask != 0) { + return i + trailing_zeroes(mask); + } + } + if (i < view.size()) { + __m128i word = + _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16)); + __m128i m1 = _mm_cmpeq_epi8(word, mask1); + __m128i m2 = _mm_cmpeq_epi8(word, mask2); + __m128i m4 = _mm_cmpeq_epi8(word, mask4); + __m128i m5 = _mm_cmpeq_epi8(word, mask5); + __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5)); + int mask = _mm_movemask_epi8(m); + if (mask != 0) { + return view.length() - 16 + trailing_zeroes(mask); + } + } + return size_t(view.length()); +} +#else +// : / [ ? +static constexpr std::array host_delimiters = []() consteval { + std::array result{}; + for (int i : {':', '/', '?', '['}) { + result[i] = 1; + } + return result; +}(); +// credit: @the-moisrex recommended a table-based approach +ada_really_inline size_t find_next_host_delimiter(std::string_view view, + size_t location) noexcept { + auto const str = view.substr(location); + for (auto pos = str.begin(); pos != str.end(); ++pos) { + if (host_delimiters[(uint8_t)*pos]) { + return pos - str.begin() + location; + } + } + return size_t(view.size()); +} +#endif + +ada_really_inline std::pair get_host_delimiter_location( + const bool is_special, std::string_view& view) noexcept { + /** + * The spec at https://url.spec.whatwg.org/#hostname-state expects us to + * compute a variable called insideBrackets but this variable is only used + * once, to check whether a ':' character was found outside brackets. Exact + * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:". + * It is conceptually simpler and arguably more efficient to just return a + * Boolean indicating whether ':' was found outside brackets. + */ + const size_t view_size = view.size(); + size_t location = 0; + bool found_colon = false; + /** + * Performance analysis: + * + * We are basically seeking the end of the hostname which can be indicated + * by the end of the view, or by one of the characters ':', '/', '?', '\\' + * (where '\\' is only applicable for special URLs). However, these must + * appear outside a bracket range. E.g., if you have [something?]fd: then the + * '?' does not count. + * + * So we can skip ahead to the next delimiter, as long as we include '[' in + * the set of delimiters, and that we handle it first. + * + * So the trick is to have a fast function that locates the next delimiter. + * Unless we find '[', then it only needs to be called once! Ideally, such a + * function would be provided by the C++ standard library, but it seems that + * find_first_of is not very fast, so we are forced to roll our own. + * + * We do not break into two loops for speed, but for clarity. + */ + if (is_special) { + // We move to the next delimiter. + location = find_next_host_delimiter_special(view, location); + // Unless we find '[' then we are going only going to have to call + // find_next_host_delimiter_special once. + for (; location < view_size; + location = find_next_host_delimiter_special(view, location)) { + if (view[location] == '[') { + location = view.find(']', location); + if (location == std::string_view::npos) { + // performance: view.find might get translated to a memchr, which + // has no notion of std::string_view::npos, so the code does not + // reflect the assembly. + location = view_size; + break; + } + } else { + found_colon = view[location] == ':'; + break; + } + } + } else { + // We move to the next delimiter. + location = find_next_host_delimiter(view, location); + // Unless we find '[' then we are going only going to have to call + // find_next_host_delimiter_special once. + for (; location < view_size; + location = find_next_host_delimiter(view, location)) { + if (view[location] == '[') { + location = view.find(']', location); + if (location == std::string_view::npos) { + // performance: view.find might get translated to a memchr, which + // has no notion of std::string_view::npos, so the code does not + // reflect the assembly. + location = view_size; + break; + } + } else { + found_colon = view[location] == ':'; + break; + } + } + } + // performance: remove_suffix may translate into a single instruction. + view.remove_suffix(view_size - location); + return {location, found_colon}; +} + +void trim_c0_whitespace(std::string_view& input) noexcept { + while (!input.empty() && + ada::unicode::is_c0_control_or_space(input.front())) { + input.remove_prefix(1); + } + while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) { + input.remove_suffix(1); + } +} + +ada_really_inline void parse_prepared_path(std::string_view input, + ada::scheme::type type, + std::string& path) { + ada_log("parse_prepared_path ", input); + uint8_t accumulator = checkers::path_signature(input); + // Let us first detect a trivial case. + // If it is special, we check that we have no dot, no %, no \ and no + // character needing percent encoding. Otherwise, we check that we have no %, + // no dot, and no character needing percent encoding. + constexpr uint8_t need_encoding = 1; + constexpr uint8_t backslash_char = 2; + constexpr uint8_t dot_char = 4; + constexpr uint8_t percent_char = 8; + bool special = type != ada::scheme::NOT_SPECIAL; + bool may_need_slow_file_handling = (type == ada::scheme::type::FILE && + checkers::is_windows_drive_letter(input)); + bool trivial_path = + (special ? (accumulator == 0) + : ((accumulator & (need_encoding | dot_char | percent_char)) == + 0)) && + (!may_need_slow_file_handling); + if (accumulator == dot_char && !may_need_slow_file_handling) { + // '4' means that we have at least one dot, but nothing that requires + // percent encoding or decoding. The only part that is not trivial is + // that we may have single dots and double dots path segments. + // If we have such segments, then we either have a path that begins + // with '.' (easy to check), or we have the sequence './'. + // Note: input cannot be empty, it must at least contain one character ('.') + // Note: we know that '\' is not present. + if (input[0] != '.') { + size_t slashdot = input.find("/."); + if (slashdot == std::string_view::npos) { // common case + trivial_path = true; + } else { // uncommon + // only three cases matter: /./, /.. or a final / + trivial_path = + !(slashdot + 2 == input.size() || input[slashdot + 2] == '.' || + input[slashdot + 2] == '/'); + } + } + } + if (trivial_path) { + ada_log("parse_path trivial"); + path += '/'; + path += input; + return; + } + // We are going to need to look a bit at the path, but let us see if we can + // ignore percent encoding *and* backslashes *and* percent characters. + // Except for the trivial case, this is likely to capture 99% of paths out + // there. + bool fast_path = + (special && + (accumulator & (need_encoding | backslash_char | percent_char)) == 0) && + (type != ada::scheme::type::FILE); + if (fast_path) { + ada_log("parse_prepared_path fast"); + // Here we don't need to worry about \ or percent encoding. + // We also do not have a file protocol. We might have dots, however, + // but dots must as appear as '.', and they cannot be encoded because + // the symbol '%' is not present. + size_t previous_location = 0; // We start at 0. + do { + size_t new_location = input.find('/', previous_location); + // std::string_view path_view = input; + // We process the last segment separately: + if (new_location == std::string_view::npos) { + std::string_view path_view = input.substr(previous_location); + if (path_view == "..") { // The path ends with .. + // e.g., if you receive ".." with an empty path, you go to "/". + if (path.empty()) { + path = '/'; + return; + } + // Fast case where we have nothing to do: + if (path.back() == '/') { + return; + } + // If you have the path "/joe/myfriend", + // then you delete 'myfriend'. + path.resize(path.rfind('/') + 1); + return; + } + path += '/'; + if (path_view != ".") { + path.append(path_view); + } + return; + } else { + // This is a non-final segment. + std::string_view path_view = + input.substr(previous_location, new_location - previous_location); + previous_location = new_location + 1; + if (path_view == "..") { + size_t last_delimiter = path.rfind('/'); + if (last_delimiter != std::string::npos) { + path.erase(last_delimiter); + } + } else if (path_view != ".") { + path += '/'; + path.append(path_view); + } + } + } while (true); + } else { + ada_log("parse_path slow"); + // we have reached the general case + bool needs_percent_encoding = (accumulator & 1); + std::string path_buffer_tmp; + do { + size_t location = (special && (accumulator & 2)) + ? input.find_first_of("/\\") + : input.find('/'); + std::string_view path_view = input; + if (location != std::string_view::npos) { + path_view.remove_suffix(path_view.size() - location); + input.remove_prefix(location + 1); + } + // path_buffer is either path_view or it might point at a percent encoded + // temporary file. + std::string_view path_buffer = + (needs_percent_encoding && + ada::unicode::percent_encode( + path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp)) + ? path_buffer_tmp + : path_view; + if (unicode::is_double_dot_path_segment(path_buffer)) { + if ((helpers::shorten_path(path, type) || special) && + location == std::string_view::npos) { + path += '/'; + } + } else if (unicode::is_single_dot_path_segment(path_buffer) && + (location == std::string_view::npos)) { + path += '/'; + } + // Otherwise, if path_buffer is not a single-dot path segment, then: + else if (!unicode::is_single_dot_path_segment(path_buffer)) { + // If url's scheme is "file", url's path is empty, and path_buffer is a + // Windows drive letter, then replace the second code point in + // path_buffer with U+003A (:). + if (type == ada::scheme::type::FILE && path.empty() && + checkers::is_windows_drive_letter(path_buffer)) { + path += '/'; + path += path_buffer[0]; + path += ':'; + path_buffer.remove_prefix(2); + path.append(path_buffer); + } else { + // Append path_buffer to url's path. + path += '/'; + path.append(path_buffer); + } + } + if (location == std::string_view::npos) { + return; + } + } while (true); + } +} + +bool overlaps(std::string_view input1, const std::string& input2) noexcept { + ada_log("helpers::overlaps check if string_view '", input1, "' [", + input1.size(), " bytes] is part of string '", input2, "' [", + input2.size(), " bytes]"); + return !input1.empty() && !input2.empty() && input1.data() >= input2.data() && + input1.data() < input2.data() + input2.size(); +} + +template +ada_really_inline void strip_trailing_spaces_from_opaque_path( + url_type& url) noexcept { + ada_log("helpers::strip_trailing_spaces_from_opaque_path"); + if (!url.has_opaque_path) return; + if (url.has_hash()) return; + if (url.has_search()) return; + + auto path = std::string(url.get_pathname()); + while (!path.empty() && path.back() == ' ') { + path.resize(path.size() - 1); + } + url.update_base_pathname(path); +} + +// @ / \\ ? +static constexpr std::array authority_delimiter_special = + []() consteval { + std::array result{}; + for (uint8_t i : {'@', '/', '\\', '?'}) { + result[i] = 1; + } + return result; + }(); +// credit: @the-moisrex recommended a table-based approach +ada_really_inline size_t +find_authority_delimiter_special(std::string_view view) noexcept { + // performance note: we might be able to gain further performance + // with SIMD instrinsics. + for (auto pos = view.begin(); pos != view.end(); ++pos) { + if (authority_delimiter_special[(uint8_t)*pos]) { + return pos - view.begin(); + } + } + return size_t(view.size()); +} + +// @ / ? +static constexpr std::array authority_delimiter = []() consteval { + std::array result{}; + for (uint8_t i : {'@', '/', '?'}) { + result[i] = 1; + } + return result; +}(); +// credit: @the-moisrex recommended a table-based approach +ada_really_inline size_t +find_authority_delimiter(std::string_view view) noexcept { + // performance note: we might be able to gain further performance + // with SIMD instrinsics. + for (auto pos = view.begin(); pos != view.end(); ++pos) { + if (authority_delimiter[(uint8_t)*pos]) { + return pos - view.begin(); + } + } + return size_t(view.size()); +} + +} // namespace ada::helpers + +namespace ada { +ada_warn_unused std::string to_string(ada::state state) { + return ada::helpers::get_state(state); +} +#undef ada_make_uint8x16_t +} // namespace ada +/* end file src/helpers.cpp */ +/* begin file src/url.cpp */ + +#include +#include +#include +#include + +namespace ada { + +bool url::parse_opaque_host(std::string_view input) { + ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); + if (std::ranges::any_of(input.begin(), input.end(), + ada::unicode::is_forbidden_host_code_point)) { + return is_valid = false; + } + + // Return the result of running UTF-8 percent-encode on input using the C0 + // control percent-encode set. + host = ada::unicode::percent_encode( + input, ada::character_sets::C0_CONTROL_PERCENT_ENCODE); + return true; +} + +bool url::parse_ipv4(std::string_view input) { + ada_log("parse_ipv4 ", input, " [", input.size(), " bytes]"); + if (input.back() == '.') { + input.remove_suffix(1); + } + size_t digit_count{0}; + int pure_decimal_count = 0; // entries that are decimal + std::string_view original_input = + input; // we might use this if pure_decimal_count == 4. + uint64_t ipv4{0}; + // we could unroll for better performance? + for (; (digit_count < 4) && !(input.empty()); digit_count++) { + uint32_t + segment_result{}; // If any number exceeds 32 bits, we have an error. + bool is_hex = checkers::has_hex_prefix(input); + if (is_hex && ((input.length() == 2) || + ((input.length() > 2) && (input[2] == '.')))) { + // special case + segment_result = 0; + input.remove_prefix(2); + } else { + std::from_chars_result r{}; + if (is_hex) { + r = std::from_chars(input.data() + 2, input.data() + input.size(), + segment_result, 16); + } else if ((input.length() >= 2) && input[0] == '0' && + checkers::is_digit(input[1])) { + r = std::from_chars(input.data() + 1, input.data() + input.size(), + segment_result, 8); + } else { + pure_decimal_count++; + r = std::from_chars(input.data(), input.data() + input.size(), + segment_result, 10); + } + if (r.ec != std::errc()) { + return is_valid = false; + } + input.remove_prefix(r.ptr - input.data()); + } + if (input.empty()) { + // We have the last value. + // At this stage, ipv4 contains digit_count*8 bits. + // So we have 32-digit_count*8 bits left. + if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) { + return is_valid = false; + } + ipv4 <<= (32 - digit_count * 8); + ipv4 |= segment_result; + goto final; + } else { + // There is more, so that the value must no be larger than 255 + // and we must have a '.'. + if ((segment_result > 255) || (input[0] != '.')) { + return is_valid = false; + } + ipv4 <<= 8; + ipv4 |= segment_result; + input.remove_prefix(1); // remove '.' + } + } + if ((digit_count != 4) || (!input.empty())) { + return is_valid = false; + } +final: + // We could also check r.ptr to see where the parsing ended. + if (pure_decimal_count == 4) { + host = original_input; // The original input was already all decimal and we + // validated it. + } else { + host = ada::serializers::ipv4(ipv4); // We have to reserialize the address. + } + host_type = IPV4; + return true; +} + +bool url::parse_ipv6(std::string_view input) { + ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]"); + + if (input.empty()) { + return is_valid = false; + } + // Let address be a new IPv6 address whose IPv6 pieces are all 0. + std::array address{}; + + // Let pieceIndex be 0. + int piece_index = 0; + + // Let compress be null. + std::optional compress{}; + + // Let pointer be a pointer for input. + std::string_view::iterator pointer = input.begin(); + + // If c is U+003A (:), then: + if (input[0] == ':') { + // If remaining does not start with U+003A (:), validation error, return + // failure. + if (input.size() == 1 || input[1] != ':') { + ada_log("parse_ipv6 starts with : but the rest does not start with :"); + return is_valid = false; + } + + // Increase pointer by 2. + pointer += 2; + + // Increase pieceIndex by 1 and then set compress to pieceIndex. + compress = ++piece_index; + } + + // While c is not the EOF code point: + while (pointer != input.end()) { + // If pieceIndex is 8, validation error, return failure. + if (piece_index == 8) { + ada_log("parse_ipv6 piece_index == 8"); + return is_valid = false; + } + + // If c is U+003A (:), then: + if (*pointer == ':') { + // If compress is non-null, validation error, return failure. + if (compress.has_value()) { + ada_log("parse_ipv6 compress is non-null"); + return is_valid = false; + } + + // Increase pointer and pieceIndex by 1, set compress to pieceIndex, and + // then continue. + pointer++; + compress = ++piece_index; + continue; + } + + // Let value and length be 0. + uint16_t value = 0, length = 0; + + // While length is less than 4 and c is an ASCII hex digit, + // set value to value times 0x10 + c interpreted as hexadecimal number, and + // increase pointer and length by 1. + while (length < 4 && pointer != input.end() && + unicode::is_ascii_hex_digit(*pointer)) { + // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int + value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer)); + pointer++; + length++; + } + + // If c is U+002E (.), then: + if (pointer != input.end() && *pointer == '.') { + // If length is 0, validation error, return failure. + if (length == 0) { + ada_log("parse_ipv6 length is 0"); + return is_valid = false; + } + + // Decrease pointer by length. + pointer -= length; + + // If pieceIndex is greater than 6, validation error, return failure. + if (piece_index > 6) { + ada_log("parse_ipv6 piece_index > 6"); + return is_valid = false; + } + + // Let numbersSeen be 0. + int numbers_seen = 0; + + // While c is not the EOF code point: + while (pointer != input.end()) { + // Let ipv4Piece be null. + std::optional ipv4_piece{}; + + // If numbersSeen is greater than 0, then: + if (numbers_seen > 0) { + // If c is a U+002E (.) and numbersSeen is less than 4, then increase + // pointer by 1. + if (*pointer == '.' && numbers_seen < 4) { + pointer++; + } + // Otherwise, validation error, return failure. + else { + ada_log("parse_ipv6 Otherwise, validation error, return failure"); + return is_valid = false; + } + } + + // If c is not an ASCII digit, validation error, return failure. + if (pointer == input.end() || !checkers::is_digit(*pointer)) { + ada_log( + "parse_ipv6 If c is not an ASCII digit, validation error, return " + "failure"); + return is_valid = false; + } + + // While c is an ASCII digit: + while (pointer != input.end() && checkers::is_digit(*pointer)) { + // Let number be c interpreted as decimal number. + int number = *pointer - '0'; + + // If ipv4Piece is null, then set ipv4Piece to number. + if (!ipv4_piece.has_value()) { + ipv4_piece = number; + } + // Otherwise, if ipv4Piece is 0, validation error, return failure. + else if (ipv4_piece == 0) { + ada_log("parse_ipv6 if ipv4Piece is 0, validation error"); + return is_valid = false; + } + // Otherwise, set ipv4Piece to ipv4Piece times 10 + number. + else { + ipv4_piece = *ipv4_piece * 10 + number; + } + + // If ipv4Piece is greater than 255, validation error, return failure. + if (ipv4_piece > 255) { + ada_log("parse_ipv6 ipv4_piece > 255"); + return is_valid = false; + } + + // Increase pointer by 1. + pointer++; + } + + // Set address[pieceIndex] to address[pieceIndex] times 0x100 + + // ipv4Piece. + // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int + address[piece_index] = + uint16_t(address[piece_index] * 0x100 + *ipv4_piece); + + // Increase numbersSeen by 1. + numbers_seen++; + + // If numbersSeen is 2 or 4, then increase pieceIndex by 1. + if (numbers_seen == 2 || numbers_seen == 4) { + piece_index++; + } + } + + // If numbersSeen is not 4, validation error, return failure. + if (numbers_seen != 4) { + return is_valid = false; + } + + // Break. + break; + } + // Otherwise, if c is U+003A (:): + else if ((pointer != input.end()) && (*pointer == ':')) { + // Increase pointer by 1. + pointer++; + + // If c is the EOF code point, validation error, return failure. + if (pointer == input.end()) { + ada_log( + "parse_ipv6 If c is the EOF code point, validation error, return " + "failure"); + return is_valid = false; + } + } + // Otherwise, if c is not the EOF code point, validation error, return + // failure. + else if (pointer != input.end()) { + ada_log( + "parse_ipv6 Otherwise, if c is not the EOF code point, validation " + "error, return failure"); + return is_valid = false; + } + + // Set address[pieceIndex] to value. + address[piece_index] = value; + + // Increase pieceIndex by 1. + piece_index++; + } + + // If compress is non-null, then: + if (compress.has_value()) { + // Let swaps be pieceIndex - compress. + int swaps = piece_index - *compress; + + // Set pieceIndex to 7. + piece_index = 7; + + // While pieceIndex is not 0 and swaps is greater than 0, + // swap address[pieceIndex] with address[compress + swaps - 1], and then + // decrease both pieceIndex and swaps by 1. + while (piece_index != 0 && swaps > 0) { + std::swap(address[piece_index], address[*compress + swaps - 1]); + piece_index--; + swaps--; + } + } + // Otherwise, if compress is null and pieceIndex is not 8, validation error, + // return failure. + else if (piece_index != 8) { + ada_log( + "parse_ipv6 if compress is null and pieceIndex is not 8, validation " + "error, return failure"); + return is_valid = false; + } + host = ada::serializers::ipv6(address); + ada_log("parse_ipv6 ", *host); + host_type = IPV6; + return true; +} + +template +ada_really_inline bool url::parse_scheme(const std::string_view input) { + auto parsed_type = ada::scheme::get_scheme_type(input); + bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); + /** + * In the common case, we will immediately recognize a special scheme (e.g., + *http, https), in which case, we can go really fast. + **/ + if (is_input_special) { // fast path!!! + if constexpr (has_state_override) { + // If url's scheme is not a special scheme and buffer is a special scheme, + // then return. + if (is_special() != is_input_special) { + return false; + } + + // If url includes credentials or has a non-null port, and buffer is + // "file", then return. + if ((has_credentials() || port.has_value()) && + parsed_type == ada::scheme::type::FILE) { + return false; + } + + // If url's scheme is "file" and its host is an empty host, then return. + // An empty host is the empty string. + if (type == ada::scheme::type::FILE && host.has_value() && + host.value().empty()) { + return false; + } + } + + type = parsed_type; + + if constexpr (has_state_override) { + // This is uncommon. + uint16_t urls_scheme_port = get_special_port(); + + if (urls_scheme_port) { + // If url's port is url's scheme's default port, then set url's port to + // null. + if (port.has_value() && *port == urls_scheme_port) { + port = std::nullopt; + } + } + } + } else { // slow path + std::string _buffer(input); + // Next function is only valid if the input is ASCII and returns false + // otherwise, but it seems that we always have ascii content so we do not + // need to check the return value. + // bool is_ascii = + unicode::to_lower_ascii(_buffer.data(), _buffer.size()); + + if constexpr (has_state_override) { + // If url's scheme is a special scheme and buffer is not a special scheme, + // then return. If url's scheme is not a special scheme and buffer is a + // special scheme, then return. + if (is_special() != ada::scheme::is_special(_buffer)) { + return true; + } + + // If url includes credentials or has a non-null port, and buffer is + // "file", then return. + if ((has_credentials() || port.has_value()) && _buffer == "file") { + return true; + } + + // If url's scheme is "file" and its host is an empty host, then return. + // An empty host is the empty string. + if (type == ada::scheme::type::FILE && host.has_value() && + host.value().empty()) { + return true; + } + } + + set_scheme(std::move(_buffer)); + + if constexpr (has_state_override) { + // This is uncommon. + uint16_t urls_scheme_port = get_special_port(); + + if (urls_scheme_port) { + // If url's port is url's scheme's default port, then set url's port to + // null. + if (port.has_value() && *port == urls_scheme_port) { + port = std::nullopt; + } + } + } + } + + return true; +} + +ada_really_inline bool url::parse_host(std::string_view input) { + ada_log("parse_host ", input, " [", input.size(), " bytes]"); + if (input.empty()) { + return is_valid = false; + } // technically unnecessary. + // If input starts with U+005B ([), then: + if (input[0] == '[') { + // If input does not end with U+005D (]), validation error, return failure. + if (input.back() != ']') { + return is_valid = false; + } + ada_log("parse_host ipv6"); + + // Return the result of IPv6 parsing input with its leading U+005B ([) and + // trailing U+005D (]) removed. + input.remove_prefix(1); + input.remove_suffix(1); + return parse_ipv6(input); + } + + // If isNotSpecial is true, then return the result of opaque-host parsing + // input. + if (!is_special()) { + return parse_opaque_host(input); + } + // Let domain be the result of running UTF-8 decode without BOM on the + // percent-decoding of input. Let asciiDomain be the result of running domain + // to ASCII with domain and false. The most common case is an ASCII input, in + // which case we do not need to call the expensive 'to_ascii' if a few + // conditions are met: no '%' and no 'xn-' subsequence. + std::string buffer = std::string(input); + // This next function checks that the result is ascii, but we are going to + // to check anyhow with is_forbidden. + // bool is_ascii = + unicode::to_lower_ascii(buffer.data(), buffer.size()); + bool is_forbidden = unicode::contains_forbidden_domain_code_point( + buffer.data(), buffer.size()); + if (is_forbidden == 0 && buffer.find("xn-") == std::string_view::npos) { + // fast path + host = std::move(buffer); + if (checkers::is_ipv4(host.value())) { + ada_log("parse_host fast path ipv4"); + return parse_ipv4(host.value()); + } + ada_log("parse_host fast path ", *host); + return true; + } + ada_log("parse_host calling to_ascii"); + is_valid = ada::unicode::to_ascii(host, input, input.find('%')); + if (!is_valid) { + ada_log("parse_host to_ascii returns false"); + return is_valid = false; + } + ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(), + " bytes]"); + + if (std::any_of(host.value().begin(), host.value().end(), + ada::unicode::is_forbidden_domain_code_point)) { + host = std::nullopt; + return is_valid = false; + } + + // If asciiDomain ends in a number, then return the result of IPv4 parsing + // asciiDomain. + if (checkers::is_ipv4(host.value())) { + ada_log("parse_host got ipv4 ", *host); + return parse_ipv4(host.value()); + } + + return true; +} + +ada_really_inline void url::parse_path(std::string_view input) { + ada_log("parse_path ", input); + std::string tmp_buffer; + std::string_view internal_input; + if (unicode::has_tabs_or_newline(input)) { + tmp_buffer = input; + // Optimization opportunity: Instead of copying and then pruning, we could + // just directly build the string from user_input. + helpers::remove_ascii_tab_or_newline(tmp_buffer); + internal_input = tmp_buffer; + } else { + internal_input = input; + } + + // If url is special, then: + if (is_special()) { + if (internal_input.empty()) { + path = "/"; + } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { + helpers::parse_prepared_path(internal_input.substr(1), type, path); + } else { + helpers::parse_prepared_path(internal_input, type, path); + } + } else if (!internal_input.empty()) { + if (internal_input[0] == '/') { + helpers::parse_prepared_path(internal_input.substr(1), type, path); + } else { + helpers::parse_prepared_path(internal_input, type, path); + } + } else { + if (!host.has_value()) { + path = "/"; + } + } +} + +[[nodiscard]] std::string url::to_string() const { + if (!is_valid) { + return "null"; + } + std::string answer; + auto back = std::back_insert_iterator(answer); + answer.append("{\n"); + answer.append("\t\"protocol\":\""); + helpers::encode_json(get_protocol(), back); + answer.append("\",\n"); + if (has_credentials()) { + answer.append("\t\"username\":\""); + helpers::encode_json(username, back); + answer.append("\",\n"); + answer.append("\t\"password\":\""); + helpers::encode_json(password, back); + answer.append("\",\n"); + } + if (host.has_value()) { + answer.append("\t\"host\":\""); + helpers::encode_json(host.value(), back); + answer.append("\",\n"); + } + if (port.has_value()) { + answer.append("\t\"port\":\""); + answer.append(std::to_string(port.value())); + answer.append("\",\n"); + } + answer.append("\t\"path\":\""); + helpers::encode_json(path, back); + answer.append("\",\n"); + answer.append("\t\"opaque path\":"); + answer.append((has_opaque_path ? "true" : "false")); + if (has_search()) { + answer.append(",\n"); + answer.append("\t\"query\":\""); + helpers::encode_json(query.value(), back); + answer.append("\""); + } + if (hash.has_value()) { + answer.append(",\n"); + answer.append("\t\"hash\":\""); + helpers::encode_json(hash.value(), back); + answer.append("\""); + } + answer.append("\n}"); + return answer; +} + +[[nodiscard]] bool url::has_valid_domain() const noexcept { + if (!host.has_value()) { + return false; + } + return checkers::verify_dns_length(host.value()); +} + +[[nodiscard]] std::string url::get_origin() const noexcept { + if (is_special()) { + // Return a new opaque origin. + if (type == scheme::FILE) { + return "null"; + } + return ada::helpers::concat(get_protocol(), "//", get_host()); + } + + if (non_special_scheme == "blob") { + if (!path.empty()) { + auto result = ada::parse(path); + if (result && + (result->type == scheme::HTTP || result->type == scheme::HTTPS)) { + // If pathURL's scheme is not "http" and not "https", then return a + // new opaque origin. + return ada::helpers::concat(result->get_protocol(), "//", + result->get_host()); + } + } + } + + // Return a new opaque origin. + return "null"; +} + +[[nodiscard]] std::string url::get_protocol() const noexcept { + if (is_special()) { + return helpers::concat(ada::scheme::details::is_special_list[type], ":"); + } + // We only move the 'scheme' if it is non-special. + return helpers::concat(non_special_scheme, ":"); +} + +[[nodiscard]] std::string url::get_host() const noexcept { + // If url's host is null, then return the empty string. + // If url's port is null, return url's host, serialized. + // Return url's host, serialized, followed by U+003A (:) and url's port, + // serialized. + if (!host.has_value()) { + return ""; + } + if (port.has_value()) { + return host.value() + ":" + get_port(); + } + return host.value(); +} + +[[nodiscard]] std::string url::get_hostname() const noexcept { + return host.value_or(""); +} + +[[nodiscard]] std::string url::get_search() const noexcept { + // If this's URL's query is either null or the empty string, then return the + // empty string. Return U+003F (?), followed by this's URL's query. + return (!query.has_value() || (query.value().empty())) ? "" + : "?" + query.value(); +} + +[[nodiscard]] const std::string& url::get_username() const noexcept { + return username; +} + +[[nodiscard]] const std::string& url::get_password() const noexcept { + return password; +} + +[[nodiscard]] std::string url::get_port() const noexcept { + return port.has_value() ? std::to_string(port.value()) : ""; +} + +[[nodiscard]] std::string url::get_hash() const noexcept { + // If this's URL's fragment is either null or the empty string, then return + // the empty string. Return U+0023 (#), followed by this's URL's fragment. + return (!hash.has_value() || (hash.value().empty())) ? "" + : "#" + hash.value(); +} + +template +bool url::set_host_or_hostname(const std::string_view input) { + if (has_opaque_path) { + return false; + } + + std::optional previous_host = host; + std::optional previous_port = port; + + size_t host_end_pos = input.find('#'); + std::string _host(input.data(), host_end_pos != std::string_view::npos + ? host_end_pos + : input.size()); + helpers::remove_ascii_tab_or_newline(_host); + std::string_view new_host(_host); + + // If url's scheme is "file", then set state to file host state, instead of + // host state. + if (type != ada::scheme::type::FILE) { + std::string_view host_view(_host.data(), _host.length()); + auto [location, found_colon] = + helpers::get_host_delimiter_location(is_special(), host_view); + + // Otherwise, if c is U+003A (:) and insideBrackets is false, then: + // Note: the 'found_colon' value is true if and only if a colon was + // encountered while not inside brackets. + if (found_colon) { + if constexpr (override_hostname) { + return false; + } + std::string_view buffer = new_host.substr(location + 1); + if (!buffer.empty()) { + set_port(buffer); + } + } + // If url is special and host_view is the empty string, validation error, + // return failure. Otherwise, if state override is given, host_view is the + // empty string, and either url includes credentials or url's port is + // non-null, return. + else if (host_view.empty() && + (is_special() || has_credentials() || port.has_value())) { + return false; + } + + // Let host be the result of host parsing host_view with url is not special. + if (host_view.empty() && !is_special()) { + host = ""; + return true; + } + + bool succeeded = parse_host(host_view); + if (!succeeded) { + host = std::move(previous_host); + update_base_port(previous_port); + } + return succeeded; + } + + size_t location = new_host.find_first_of("/\\?"); + if (location != std::string_view::npos) { + new_host.remove_suffix(new_host.length() - location); + } + + if (new_host.empty()) { + // Set url's host to the empty string. + host = ""; + } else { + // Let host be the result of host parsing buffer with url is not special. + if (!parse_host(new_host)) { + host = std::move(previous_host); + update_base_port(previous_port); + return false; + } + + // If host is "localhost", then set host to the empty string. + if (host == "localhost") { + host = ""; + } + } + return true; +} + +bool url::set_host(const std::string_view input) { + return set_host_or_hostname(input); +} + +bool url::set_hostname(const std::string_view input) { + return set_host_or_hostname(input); +} + +bool url::set_username(const std::string_view input) { + if (cannot_have_credentials_or_port()) { + return false; + } + username = ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE); + return true; +} + +bool url::set_password(const std::string_view input) { + if (cannot_have_credentials_or_port()) { + return false; + } + password = ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE); + return true; +} + +bool url::set_port(const std::string_view input) { + if (cannot_have_credentials_or_port()) { + return false; + } + std::string trimmed(input); + helpers::remove_ascii_tab_or_newline(trimmed); + if (trimmed.empty()) { + port = std::nullopt; + return true; + } + + // Input should not start with a non-digit character. + if (!ada::unicode::is_ascii_digit(trimmed.front())) { + return false; + } + + // Revert changes if parse_port fails. + std::optional previous_port = port; + parse_port(trimmed); + if (is_valid) { + return true; + } + port = std::move(previous_port); + is_valid = true; + return false; +} + +void url::set_hash(const std::string_view input) { + if (input.empty()) { + hash = std::nullopt; + helpers::strip_trailing_spaces_from_opaque_path(*this); + return; + } + + std::string new_value; + new_value = input[0] == '#' ? input.substr(1) : input; + helpers::remove_ascii_tab_or_newline(new_value); + hash = unicode::percent_encode(new_value, + ada::character_sets::FRAGMENT_PERCENT_ENCODE); +} + +void url::set_search(const std::string_view input) { + if (input.empty()) { + query = std::nullopt; + helpers::strip_trailing_spaces_from_opaque_path(*this); + return; + } + + std::string new_value; + new_value = input[0] == '?' ? input.substr(1) : input; + helpers::remove_ascii_tab_or_newline(new_value); + + auto query_percent_encode_set = + is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE + : ada::character_sets::QUERY_PERCENT_ENCODE; + + query = ada::unicode::percent_encode(new_value, query_percent_encode_set); +} + +bool url::set_pathname(const std::string_view input) { + if (has_opaque_path) { + return false; + } + path.clear(); + parse_path(input); + return true; +} + +bool url::set_protocol(const std::string_view input) { + std::string view(input); + helpers::remove_ascii_tab_or_newline(view); + if (view.empty()) { + return true; + } + + // Schemes should start with alpha values. + if (!checkers::is_alpha(view[0])) { + return false; + } + + view.append(":"); + + std::string::iterator pointer = + std::ranges::find_if_not(view, unicode::is_alnum_plus); + + if (pointer != view.end() && *pointer == ':') { + return parse_scheme( + std::string_view(view.data(), pointer - view.begin())); + } + return false; +} + +bool url::set_href(const std::string_view input) { + ada::result out = ada::parse(input); + + if (out) { + *this = *out; + } + + return out.has_value(); +} + +} // namespace ada +/* end file src/url.cpp */ +/* begin file src/parser.cpp */ + +#include + + +namespace ada::parser { + +template +result_type parse_url_impl(std::string_view user_input, + const result_type* base_url) { + // We can specialize the implementation per type. + // Important: result_type_is_ada_url is evaluated at *compile time*. This + // means that doing if constexpr(result_type_is_ada_url) { something } else { + // something else } is free (at runtime). This means that ada::url_aggregator + // and ada::url **do not have to support the exact same API**. + constexpr bool result_type_is_ada_url = std::is_same_v; + constexpr bool result_type_is_ada_url_aggregator = + std::is_same_v; + static_assert(result_type_is_ada_url || + result_type_is_ada_url_aggregator); // We don't support + // anything else for now. + + ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(), + " bytes],", (base_url != nullptr ? base_url->to_string() : "null"), + ")"); + + state state = state::SCHEME_START; + result_type url{}; + + // We refuse to parse URL strings that exceed 4GB. Such strings are almost + // surely the result of a bug or are otherwise a security concern. + if (user_input.size() > std::numeric_limits::max()) [[unlikely]] { + url.is_valid = false; + } + // Going forward, user_input.size() is in [0, + // std::numeric_limits::max). If we are provided with an invalid + // base, or the optional_url was invalid, we must return. + if (base_url != nullptr) { + url.is_valid &= base_url->is_valid; + } + if (!url.is_valid) { + return url; + } + if constexpr (result_type_is_ada_url_aggregator && store_values) { + // Most of the time, we just need user_input.size(). + // In some instances, we may need a bit more. + /////////////////////////// + // This is *very* important. This line should *not* be removed + // hastily. There are principled reasons why reserve is important + // for performance. If you have a benchmark with small inputs, + // it may not matter, but in other instances, it could. + //// + // This rounds up to the next power of two. + // We know that user_input.size() is in [0, + // std::numeric_limits::max). + uint32_t reserve_capacity = + (0xFFFFFFFF >> + helpers::leading_zeroes(uint32_t(1 | user_input.size()))) + + 1; + url.reserve(reserve_capacity); + } + std::string tmp_buffer; + std::string_view url_data; + if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] { + tmp_buffer = user_input; + // Optimization opportunity: Instead of copying and then pruning, we could + // just directly build the string from user_input. + helpers::remove_ascii_tab_or_newline(tmp_buffer); + url_data = tmp_buffer; + } else [[likely]] { + url_data = user_input; + } + + // Leading and trailing control characters are uncommon and easy to deal with + // (no performance concern). + helpers::trim_c0_whitespace(url_data); + + // Optimization opportunity. Most websites do not have fragment. + std::optional fragment = helpers::prune_hash(url_data); + // We add it last so that an implementation like ada::url_aggregator + // can append it last to its internal buffer, thus improving performance. + + // Here url_data no longer has its fragment. + // We are going to access the data from url_data (it is immutable). + // At any given time, we are pointing at byte 'input_position' in url_data. + // The input_position variable should range from 0 to input_size. + // It is illegal to access url_data at input_size. + size_t input_position = 0; + const size_t input_size = url_data.size(); + // Keep running the following state machine by switching on state. + // If after a run pointer points to the EOF code point, go to the next step. + // Otherwise, increase pointer by 1 and continue with the state machine. + // We never decrement input_position. + while (input_position <= input_size) { + ada_log("In parsing at ", input_position, " out of ", input_size, + " in state ", ada::to_string(state)); + switch (state) { + case state::SCHEME_START: { + ada_log("SCHEME_START ", helpers::substring(url_data, input_position)); + // If c is an ASCII alpha, append c, lowercased, to buffer, and set + // state to scheme state. + if ((input_position != input_size) && + checkers::is_alpha(url_data[input_position])) { + state = state::SCHEME; + input_position++; + } else { + // Otherwise, if state override is not given, set state to no scheme + // state and decrease pointer by 1. + state = state::NO_SCHEME; + } + break; + } + case state::SCHEME: { + ada_log("SCHEME ", helpers::substring(url_data, input_position)); + // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), + // append c, lowercased, to buffer. + while ((input_position != input_size) && + (unicode::is_alnum_plus(url_data[input_position]))) { + input_position++; + } + // Otherwise, if c is U+003A (:), then: + if ((input_position != input_size) && + (url_data[input_position] == ':')) { + ada_log("SCHEME the scheme should be ", + url_data.substr(0, input_position)); + if constexpr (result_type_is_ada_url) { + if (!url.parse_scheme(url_data.substr(0, input_position))) { + return url; + } + } else { + // we pass the colon along instead of painfully adding it back. + if (!url.parse_scheme_with_colon( + url_data.substr(0, input_position + 1))) { + return url; + } + } + ada_log("SCHEME the scheme is ", url.get_protocol()); + + // If url's scheme is "file", then: + if (url.type == scheme::type::FILE) { + // Set state to file state. + state = state::FILE; + } + // Otherwise, if url is special, base is non-null, and base's scheme + // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url + // != nullptr is false. + else if (url.is_special() && base_url != nullptr && + base_url->type == url.type) { + // Set state to special relative or authority state. + state = state::SPECIAL_RELATIVE_OR_AUTHORITY; + } + // Otherwise, if url is special, set state to special authority + // slashes state. + else if (url.is_special()) { + state = state::SPECIAL_AUTHORITY_SLASHES; + } + // Otherwise, if remaining starts with an U+002F (/), set state to + // path or authority state and increase pointer by 1. + else if (input_position + 1 < input_size && + url_data[input_position + 1] == '/') { + state = state::PATH_OR_AUTHORITY; + input_position++; + } + // Otherwise, set url's path to the empty string and set state to + // opaque path state. + else { + state = state::OPAQUE_PATH; + } + } + // Otherwise, if state override is not given, set buffer to the empty + // string, state to no scheme state, and start over (from the first code + // point in input). + else { + state = state::NO_SCHEME; + input_position = 0; + break; + } + input_position++; + break; + } + case state::NO_SCHEME: { + ada_log("NO_SCHEME ", helpers::substring(url_data, input_position)); + // If base is null, or base has an opaque path and c is not U+0023 (#), + // validation error, return failure. + if (base_url == nullptr || + (base_url->has_opaque_path && !fragment.has_value())) { + ada_log("NO_SCHEME validation error"); + url.is_valid = false; + return url; + } + // Otherwise, if base has an opaque path and c is U+0023 (#), + // set url's scheme to base's scheme, url's path to base's path, url's + // query to base's query, and set state to fragment state. + else if (base_url->has_opaque_path && fragment.has_value() && + input_position == input_size) { + ada_log("NO_SCHEME opaque base with fragment"); + url.copy_scheme(*base_url); + url.has_opaque_path = base_url->has_opaque_path; + + if constexpr (result_type_is_ada_url) { + url.path = base_url->path; + url.query = base_url->query; + } else { + url.update_base_pathname(base_url->get_pathname()); + url.update_base_search(base_url->get_search()); + } + url.update_unencoded_base_hash(*fragment); + return url; + } + // Otherwise, if base's scheme is not "file", set state to relative + // state and decrease pointer by 1. + else if (base_url->type != scheme::type::FILE) { + ada_log("NO_SCHEME non-file relative path"); + state = state::RELATIVE_SCHEME; + } + // Otherwise, set state to file state and decrease pointer by 1. + else { + ada_log("NO_SCHEME file base type"); + state = state::FILE; + } + break; + } + case state::AUTHORITY: { + ada_log("AUTHORITY ", helpers::substring(url_data, input_position)); + // most URLs have no @. Having no @ tells us that we don't have to worry + // about AUTHORITY. Of course, we could have @ and still not have to + // worry about AUTHORITY. + // TODO: Instead of just collecting a bool, collect the location of the + // '@' and do something useful with it. + // TODO: We could do various processing early on, using a single pass + // over the string to collect information about it, e.g., telling us + // whether there is a @ and if so, where (or how many). + + // Check if url data contains an @. + if (url_data.find('@', input_position) == std::string_view::npos) { + state = state::HOST; + break; + } + bool at_sign_seen{false}; + bool password_token_seen{false}; + /** + * We expect something of the sort... + * https://user:pass@example.com:1234/foo/bar?baz#quux + * --------^ + */ + do { + std::string_view view = url_data.substr(input_position); + // The delimiters are @, /, ? \\. + size_t location = + url.is_special() ? helpers::find_authority_delimiter_special(view) + : helpers::find_authority_delimiter(view); + std::string_view authority_view = view.substr(0, location); + size_t end_of_authority = input_position + authority_view.size(); + // If c is U+0040 (@), then: + if ((end_of_authority != input_size) && + (url_data[end_of_authority] == '@')) { + // If atSignSeen is true, then prepend "%40" to buffer. + if (at_sign_seen) { + if (password_token_seen) { + if constexpr (result_type_is_ada_url) { + url.password += "%40"; + } else { + url.append_base_password("%40"); + } + } else { + if constexpr (result_type_is_ada_url) { + url.username += "%40"; + } else { + url.append_base_username("%40"); + } + } + } + + at_sign_seen = true; + + if (!password_token_seen) { + size_t password_token_location = authority_view.find(':'); + password_token_seen = + password_token_location != std::string_view::npos; + + if constexpr (store_values) { + if (!password_token_seen) { + if constexpr (result_type_is_ada_url) { + url.username += unicode::percent_encode( + authority_view, + character_sets::USERINFO_PERCENT_ENCODE); + } else { + url.append_base_username(unicode::percent_encode( + authority_view, + character_sets::USERINFO_PERCENT_ENCODE)); + } + } else { + if constexpr (result_type_is_ada_url) { + url.username += unicode::percent_encode( + authority_view.substr(0, password_token_location), + character_sets::USERINFO_PERCENT_ENCODE); + url.password += unicode::percent_encode( + authority_view.substr(password_token_location + 1), + character_sets::USERINFO_PERCENT_ENCODE); + } else { + url.append_base_username(unicode::percent_encode( + authority_view.substr(0, password_token_location), + character_sets::USERINFO_PERCENT_ENCODE)); + url.append_base_password(unicode::percent_encode( + authority_view.substr(password_token_location + 1), + character_sets::USERINFO_PERCENT_ENCODE)); + } + } + } + } else if constexpr (store_values) { + if constexpr (result_type_is_ada_url) { + url.password += unicode::percent_encode( + authority_view, character_sets::USERINFO_PERCENT_ENCODE); + } else { + url.append_base_password(unicode::percent_encode( + authority_view, character_sets::USERINFO_PERCENT_ENCODE)); + } + } + } + // Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + else if (end_of_authority == input_size || + url_data[end_of_authority] == '/' || + url_data[end_of_authority] == '?' || + (url.is_special() && url_data[end_of_authority] == '\\')) { + // If atSignSeen is true and authority_view is the empty string, + // validation error, return failure. + if (at_sign_seen && authority_view.empty()) { + url.is_valid = false; + return url; + } + state = state::HOST; + break; + } + if (end_of_authority == input_size) { + if constexpr (store_values) { + if (fragment.has_value()) { + url.update_unencoded_base_hash(*fragment); + } + } + return url; + } + input_position = end_of_authority + 1; + } while (true); + + break; + } + case state::SPECIAL_RELATIVE_OR_AUTHORITY: { + ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ", + helpers::substring(url_data, input_position)); + + // If c is U+002F (/) and remaining starts with U+002F (/), + // then set state to special authority ignore slashes state and increase + // pointer by 1. + if (url_data.substr(input_position, 2) == "//") { + state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; + input_position += 2; + } else { + // Otherwise, validation error, set state to relative state and + // decrease pointer by 1. + state = state::RELATIVE_SCHEME; + } + + break; + } + case state::PATH_OR_AUTHORITY: { + ada_log("PATH_OR_AUTHORITY ", + helpers::substring(url_data, input_position)); + + // If c is U+002F (/), then set state to authority state. + if ((input_position != input_size) && + (url_data[input_position] == '/')) { + state = state::AUTHORITY; + input_position++; + } else { + // Otherwise, set state to path state, and decrease pointer by 1. + state = state::PATH; + } + + break; + } + case state::RELATIVE_SCHEME: { + ada_log("RELATIVE_SCHEME ", + helpers::substring(url_data, input_position)); + + // Set url's scheme to base's scheme. + url.copy_scheme(*base_url); + + // If c is U+002F (/), then set state to relative slash state. + if ((input_position != input_size) && + (url_data[input_position] == '/')) { + ada_log( + "RELATIVE_SCHEME if c is U+002F (/), then set state to relative " + "slash state"); + state = state::RELATIVE_SLASH; + } else if (url.is_special() && (input_position != input_size) && + (url_data[input_position] == '\\')) { + // Otherwise, if url is special and c is U+005C (\), validation error, + // set state to relative slash state. + ada_log( + "RELATIVE_SCHEME if url is special and c is U+005C, validation " + "error, set state to relative slash state"); + state = state::RELATIVE_SLASH; + } else { + ada_log("RELATIVE_SCHEME otherwise"); + // Set url's username to base's username, url's password to base's + // password, url's host to base's host, url's port to base's port, + // url's path to a clone of base's path, and url's query to base's + // query. + if constexpr (result_type_is_ada_url) { + url.username = base_url->username; + url.password = base_url->password; + url.host = base_url->host; + url.port = base_url->port; + // cloning the base path includes cloning the has_opaque_path flag + url.has_opaque_path = base_url->has_opaque_path; + url.path = base_url->path; + url.query = base_url->query; + } else { + url.update_base_authority(base_url->get_href(), + base_url->get_components()); + url.update_host_to_base_host(base_url->get_hostname()); + url.update_base_port(base_url->retrieve_base_port()); + // cloning the base path includes cloning the has_opaque_path flag + url.has_opaque_path = base_url->has_opaque_path; + url.update_base_pathname(base_url->get_pathname()); + url.update_base_search(base_url->get_search()); + } + + url.has_opaque_path = base_url->has_opaque_path; + + // If c is U+003F (?), then set url's query to the empty string, and + // state to query state. + if ((input_position != input_size) && + (url_data[input_position] == '?')) { + state = state::QUERY; + } + // Otherwise, if c is not the EOF code point: + else if (input_position != input_size) { + // Set url's query to null. + url.clear_search(); + if constexpr (result_type_is_ada_url) { + // Shorten url's path. + helpers::shorten_path(url.path, url.type); + } else { + std::string_view path = url.get_pathname(); + if (helpers::shorten_path(path, url.type)) { + url.update_base_pathname(std::move(std::string(path))); + } + } + // Set state to path state and decrease pointer by 1. + state = state::PATH; + break; + } + } + input_position++; + break; + } + case state::RELATIVE_SLASH: { + ada_log("RELATIVE_SLASH ", + helpers::substring(url_data, input_position)); + + // If url is special and c is U+002F (/) or U+005C (\), then: + if (url.is_special() && (input_position != input_size) && + (url_data[input_position] == '/' || + url_data[input_position] == '\\')) { + // Set state to special authority ignore slashes state. + state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES; + } + // Otherwise, if c is U+002F (/), then set state to authority state. + else if ((input_position != input_size) && + (url_data[input_position] == '/')) { + state = state::AUTHORITY; + } + // Otherwise, set + // - url's username to base's username, + // - url's password to base's password, + // - url's host to base's host, + // - url's port to base's port, + // - state to path state, and then, decrease pointer by 1. + else { + if constexpr (result_type_is_ada_url) { + url.username = base_url->username; + url.password = base_url->password; + url.host = base_url->host; + url.port = base_url->port; + } else { + url.update_base_authority(base_url->get_href(), + base_url->get_components()); + url.update_host_to_base_host(base_url->get_hostname()); + url.update_base_port(base_url->retrieve_base_port()); + } + state = state::PATH; + break; + } + + input_position++; + break; + } + case state::SPECIAL_AUTHORITY_SLASHES: { + ada_log("SPECIAL_AUTHORITY_SLASHES ", + helpers::substring(url_data, input_position)); + + // If c is U+002F (/) and remaining starts with U+002F (/), + // then set state to special authority ignore slashes state and increase + // pointer by 1. + if (url_data.substr(input_position, 2) == "//") { + input_position += 2; + } + + [[fallthrough]]; + } + case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: { + ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ", + helpers::substring(url_data, input_position)); + + // If c is neither U+002F (/) nor U+005C (\), then set state to + // authority state and decrease pointer by 1. + while ((input_position != input_size) && + ((url_data[input_position] == '/') || + (url_data[input_position] == '\\'))) { + input_position++; + } + state = state::AUTHORITY; + + break; + } + case state::QUERY: { + ada_log("QUERY ", helpers::substring(url_data, input_position)); + if constexpr (store_values) { + // Let queryPercentEncodeSet be the special-query percent-encode set + // if url is special; otherwise the query percent-encode set. + const uint8_t* query_percent_encode_set = + url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE + : character_sets::QUERY_PERCENT_ENCODE; + + // Percent-encode after encoding, with encoding, buffer, and + // queryPercentEncodeSet, and append the result to url's query. + url.update_base_search(url_data.substr(input_position), + query_percent_encode_set); + ada_log("QUERY update_base_search completed "); + if (fragment.has_value()) { + url.update_unencoded_base_hash(*fragment); + } + } + return url; + } + case state::HOST: { + ada_log("HOST ", helpers::substring(url_data, input_position)); + + std::string_view host_view = url_data.substr(input_position); + auto [location, found_colon] = + helpers::get_host_delimiter_location(url.is_special(), host_view); + input_position = (location != std::string_view::npos) + ? input_position + location + : input_size; + // Otherwise, if c is U+003A (:) and insideBrackets is false, then: + // Note: the 'found_colon' value is true if and only if a colon was + // encountered while not inside brackets. + if (found_colon) { + // If buffer is the empty string, validation error, return failure. + // Let host be the result of host parsing buffer with url is not + // special. + ada_log("HOST parsing ", host_view); + if (!url.parse_host(host_view)) { + return url; + } + ada_log("HOST parsing results in ", url.get_hostname()); + // Set url's host to host, buffer to the empty string, and state to + // port state. + state = state::PORT; + input_position++; + } + // Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + // The get_host_delimiter_location function either brings us to + // the colon outside of the bracket, or to one of those characters. + else { + // If url is special and host_view is the empty string, validation + // error, return failure. + if (host_view.empty() && url.is_special()) { + url.is_valid = false; + return url; + } + ada_log("HOST parsing ", host_view, " href=", url.get_href()); + // Let host be the result of host parsing host_view with url is not + // special. + if (host_view.empty()) { + url.update_base_hostname(""); + } else if (!url.parse_host(host_view)) { + return url; + } + ada_log("HOST parsing results in ", url.get_hostname(), + " href=", url.get_href()); + + // Set url's host to host, and state to path start state. + state = state::PATH_START; + } + + break; + } + case state::OPAQUE_PATH: { + ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position)); + std::string_view view = url_data.substr(input_position); + // If c is U+003F (?), then set url's query to the empty string and + // state to query state. + size_t location = view.find('?'); + if (location != std::string_view::npos) { + view.remove_suffix(view.size() - location); + state = state::QUERY; + input_position += location + 1; + } else { + input_position = input_size + 1; + } + url.has_opaque_path = true; + // This is a really unlikely scenario in real world. We should not seek + // to optimize it. + url.update_base_pathname(unicode::percent_encode( + view, character_sets::C0_CONTROL_PERCENT_ENCODE)); + break; + } + case state::PORT: { + ada_log("PORT ", helpers::substring(url_data, input_position)); + std::string_view port_view = url_data.substr(input_position); + input_position += url.parse_port(port_view, true); + if (!url.is_valid) { + return url; + } + state = state::PATH_START; + [[fallthrough]]; + } + case state::PATH_START: { + ada_log("PATH_START ", helpers::substring(url_data, input_position)); + + // If url is special, then: + if (url.is_special()) { + // Set state to path state. + state = state::PATH; + + // Optimization: Avoiding going into PATH state improves the + // performance of urls ending with /. + if (input_position == input_size) { + if constexpr (store_values) { + url.update_base_pathname("/"); + if (fragment.has_value()) { + url.update_unencoded_base_hash(*fragment); + } + } + return url; + } + // If c is neither U+002F (/) nor U+005C (\), then decrease pointer + // by 1. We know that (input_position == input_size) is impossible + // here, because of the previous if-check. + if ((url_data[input_position] != '/') && + (url_data[input_position] != '\\')) { + break; + } + } + // Otherwise, if state override is not given and c is U+003F (?), + // set url's query to the empty string and state to query state. + else if ((input_position != input_size) && + (url_data[input_position] == '?')) { + state = state::QUERY; + } + // Otherwise, if c is not the EOF code point: + else if (input_position != input_size) { + // Set state to path state. + state = state::PATH; + + // If c is not U+002F (/), then decrease pointer by 1. + if (url_data[input_position] != '/') { + break; + } + } + + input_position++; + break; + } + case state::PATH: { + ada_log("PATH ", helpers::substring(url_data, input_position)); + std::string_view view = url_data.substr(input_position); + + // Most time, we do not need percent encoding. + // Furthermore, we can immediately locate the '?'. + size_t locofquestionmark = view.find('?'); + if (locofquestionmark != std::string_view::npos) { + state = state::QUERY; + view.remove_suffix(view.size() - locofquestionmark); + input_position += locofquestionmark + 1; + } else { + input_position = input_size + 1; + } + if constexpr (store_values) { + if constexpr (result_type_is_ada_url) { + helpers::parse_prepared_path(view, url.type, url.path); + } else { + url.consume_prepared_path(view); + ADA_ASSERT_TRUE(url.validate()); + } + } + break; + } + case state::FILE_SLASH: { + ada_log("FILE_SLASH ", helpers::substring(url_data, input_position)); + + // If c is U+002F (/) or U+005C (\), then: + if ((input_position != input_size) && + (url_data[input_position] == '/' || + url_data[input_position] == '\\')) { + ada_log("FILE_SLASH c is U+002F or U+005C"); + // Set state to file host state. + state = state::FILE_HOST; + input_position++; + } else { + ada_log("FILE_SLASH otherwise"); + // If base is non-null and base's scheme is "file", then: + // Note: it is unsafe to do base_url->scheme unless you know that + // base_url_has_value() is true. + if (base_url != nullptr && base_url->type == scheme::type::FILE) { + // Set url's host to base's host. + if constexpr (result_type_is_ada_url) { + url.host = base_url->host; + } else { + url.update_host_to_base_host(base_url->get_host()); + } + // If the code point substring from pointer to the end of input does + // not start with a Windows drive letter and base's path[0] is a + // normalized Windows drive letter, then append base's path[0] to + // url's path. + if (!base_url->get_pathname().empty()) { + if (!checkers::is_windows_drive_letter( + url_data.substr(input_position))) { + std::string_view first_base_url_path = + base_url->get_pathname().substr(1); + size_t loc = first_base_url_path.find('/'); + if (loc != std::string_view::npos) { + helpers::resize(first_base_url_path, loc); + } + if (checkers::is_normalized_windows_drive_letter( + first_base_url_path)) { + if constexpr (result_type_is_ada_url) { + url.path += '/'; + url.path += first_base_url_path; + } else { + url.append_base_pathname( + helpers::concat("/", first_base_url_path)); + } + } + } + } + } + + // Set state to path state, and decrease pointer by 1. + state = state::PATH; + } + + break; + } + case state::FILE_HOST: { + ada_log("FILE_HOST ", helpers::substring(url_data, input_position)); + std::string_view view = url_data.substr(input_position); + + size_t location = view.find_first_of("/\\?"); + std::string_view file_host_buffer( + view.data(), + (location != std::string_view::npos) ? location : view.size()); + + if (checkers::is_windows_drive_letter(file_host_buffer)) { + state = state::PATH; + } else if (file_host_buffer.empty()) { + // Set url's host to the empty string. + if constexpr (result_type_is_ada_url) { + url.host = ""; + } else { + url.update_base_hostname(""); + } + // Set state to path start state. + state = state::PATH_START; + } else { + size_t consumed_bytes = file_host_buffer.size(); + input_position += consumed_bytes; + // Let host be the result of host parsing buffer with url is not + // special. + if (!url.parse_host(file_host_buffer)) { + return url; + } + + if constexpr (result_type_is_ada_url) { + // If host is "localhost", then set host to the empty string. + if (url.host.has_value() && url.host.value() == "localhost") { + url.host = ""; + } + } else { + if (url.get_hostname() == "localhost") { + url.update_base_hostname(""); + } + } + + // Set buffer to the empty string and state to path start state. + state = state::PATH_START; + } + + break; + } + case state::FILE: { + ada_log("FILE ", helpers::substring(url_data, input_position)); + std::string_view file_view = url_data.substr(input_position); + + url.set_protocol_as_file(); + if constexpr (result_type_is_ada_url) { + // Set url's host to the empty string. + url.host = ""; + } else { + url.update_base_hostname(""); + } + // If c is U+002F (/) or U+005C (\), then: + if (input_position != input_size && + (url_data[input_position] == '/' || + url_data[input_position] == '\\')) { + ada_log("FILE c is U+002F or U+005C"); + // Set state to file slash state. + state = state::FILE_SLASH; + } + // Otherwise, if base is non-null and base's scheme is "file": + else if (base_url != nullptr && base_url->type == scheme::type::FILE) { + // Set url's host to base's host, url's path to a clone of base's + // path, and url's query to base's query. + ada_log("FILE base non-null"); + if constexpr (result_type_is_ada_url) { + url.host = base_url->host; + url.path = base_url->path; + url.query = base_url->query; + } else { + url.update_host_to_base_host(base_url->get_hostname()); + url.update_base_pathname(base_url->get_pathname()); + url.update_base_search(base_url->get_search()); + } + url.has_opaque_path = base_url->has_opaque_path; + + // If c is U+003F (?), then set url's query to the empty string and + // state to query state. + if (input_position != input_size && url_data[input_position] == '?') { + state = state::QUERY; + } + // Otherwise, if c is not the EOF code point: + else if (input_position != input_size) { + // Set url's query to null. + url.clear_search(); + // If the code point substring from pointer to the end of input does + // not start with a Windows drive letter, then shorten url's path. + if (!checkers::is_windows_drive_letter(file_view)) { + if constexpr (result_type_is_ada_url) { + helpers::shorten_path(url.path, url.type); + } else { + std::string_view path = url.get_pathname(); + if (helpers::shorten_path(path, url.type)) { + url.update_base_pathname(std::move(std::string(path))); + } + } + } + // Otherwise: + else { + // Set url's path to an empty list. + url.clear_pathname(); + url.has_opaque_path = true; + } + + // Set state to path state and decrease pointer by 1. + state = state::PATH; + break; + } + } + // Otherwise, set state to path state, and decrease pointer by 1. + else { + ada_log("FILE go to path"); + state = state::PATH; + break; + } + + input_position++; + break; + } + default: + unreachable(); + } + } + if constexpr (store_values) { + if (fragment.has_value()) { + url.update_unencoded_base_hash(*fragment); + } + } + return url; +} + +template url parse_url_impl(std::string_view user_input, + const url* base_url = nullptr); +template url_aggregator parse_url_impl( + std::string_view user_input, const url_aggregator* base_url = nullptr); + +template +result_type parse_url(std::string_view user_input, + const result_type* base_url) { + return parse_url_impl(user_input, base_url); +} + +template url parse_url(std::string_view user_input, + const url* base_url = nullptr); +template url_aggregator parse_url( + std::string_view user_input, const url_aggregator* base_url = nullptr); +} // namespace ada::parser +/* end file src/parser.cpp */ +/* begin file src/url_components.cpp */ + +#include + +namespace ada { + +[[nodiscard]] std::string url_components::to_string() const { + std::string answer; + auto back = std::back_insert_iterator(answer); + answer.append("{\n"); + + answer.append("\t\"protocol_end\":\""); + helpers::encode_json(std::to_string(protocol_end), back); + answer.append("\",\n"); + + answer.append("\t\"username_end\":\""); + helpers::encode_json(std::to_string(username_end), back); + answer.append("\",\n"); + + answer.append("\t\"host_start\":\""); + helpers::encode_json(std::to_string(host_start), back); + answer.append("\",\n"); + + answer.append("\t\"host_end\":\""); + helpers::encode_json(std::to_string(host_end), back); + answer.append("\",\n"); + + answer.append("\t\"port\":\""); + helpers::encode_json(std::to_string(port), back); + answer.append("\",\n"); + + answer.append("\t\"pathname_start\":\""); + helpers::encode_json(std::to_string(pathname_start), back); + answer.append("\",\n"); + + answer.append("\t\"search_start\":\""); + helpers::encode_json(std::to_string(search_start), back); + answer.append("\",\n"); + + answer.append("\t\"hash_start\":\""); + helpers::encode_json(std::to_string(hash_start), back); + answer.append("\",\n"); + + answer.append("\n}"); + return answer; +} + +} // namespace ada +/* end file src/url_components.cpp */ +/* begin file src/url_aggregator.cpp */ + +#include +#include + +namespace ada { +template +[[nodiscard]] ada_really_inline bool url_aggregator::parse_scheme_with_colon( + const std::string_view input_with_colon) { + ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer)); + std::string_view input{input_with_colon}; + input.remove_suffix(1); + auto parsed_type = ada::scheme::get_scheme_type(input); + const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL); + /** + * In the common case, we will immediately recognize a special scheme (e.g., + *http, https), in which case, we can go really fast. + **/ + if (is_input_special) { // fast path!!! + if constexpr (has_state_override) { + // If url's scheme is not a special scheme and buffer is a special scheme, + // then return. + if (is_special() != is_input_special) { + return false; + } + + // If url includes credentials or has a non-null port, and buffer is + // "file", then return. + if ((has_credentials() || components.port != url_components::omitted) && + parsed_type == ada::scheme::type::FILE) { + return false; + } + + // If url's scheme is "file" and its host is an empty host, then return. + // An empty host is the empty string. + if (type == ada::scheme::type::FILE && + components.host_start == components.host_end) { + return false; + } + } + + type = parsed_type; + set_scheme_from_view_with_colon(input_with_colon); + + if constexpr (has_state_override) { + // This is uncommon. + uint16_t urls_scheme_port = get_special_port(); + + // If url's port is url's scheme's default port, then set url's port to + // null. + if (components.port == urls_scheme_port) { + clear_port(); + } + } + } else { // slow path + std::string _buffer(input); + // Next function is only valid if the input is ASCII and returns false + // otherwise, but it seems that we always have ascii content so we do not + // need to check the return value. + unicode::to_lower_ascii(_buffer.data(), _buffer.size()); + + if constexpr (has_state_override) { + // If url's scheme is a special scheme and buffer is not a special scheme, + // then return. If url's scheme is not a special scheme and buffer is a + // special scheme, then return. + if (is_special() != ada::scheme::is_special(_buffer)) { + return true; + } + + // If url includes credentials or has a non-null port, and buffer is + // "file", then return. + if ((has_credentials() || components.port != url_components::omitted) && + _buffer == "file") { + return true; + } + + // If url's scheme is "file" and its host is an empty host, then return. + // An empty host is the empty string. + if (type == ada::scheme::type::FILE && + components.host_start == components.host_end) { + return true; + } + } + + set_scheme(_buffer); + + if constexpr (has_state_override) { + // This is uncommon. + uint16_t urls_scheme_port = get_special_port(); + + // If url's port is url's scheme's default port, then set url's port to + // null. + if (components.port == urls_scheme_port) { + clear_port(); + } + } + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +inline void url_aggregator::copy_scheme(const url_aggregator& u) noexcept { + ada_log("url_aggregator::copy_scheme ", u.buffer); + ADA_ASSERT_TRUE(validate()); + // next line could overflow but unsigned arithmetic has well-defined + // overflows. + uint32_t new_difference = u.components.protocol_end - components.protocol_end; + type = u.type; + buffer.erase(0, components.protocol_end); + buffer.insert(0, u.get_protocol()); + components.protocol_end = u.components.protocol_end; + + // No need to update the components + if (new_difference == 0) { + return; + } + + // Update the rest of the components. + components.username_end += new_difference; + components.host_start += new_difference; + components.host_end += new_difference; + components.pathname_start += new_difference; + if (components.search_start != url_components::omitted) { + components.search_start += new_difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += new_difference; + } + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::set_scheme_from_view_with_colon( + std::string_view new_scheme_with_colon) noexcept { + ada_log("url_aggregator::set_scheme_from_view_with_colon ", + new_scheme_with_colon); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() && + new_scheme_with_colon.back() == ':'); + // next line could overflow but unsigned arithmetic has well-defined + // overflows. + uint32_t new_difference = + uint32_t(new_scheme_with_colon.size()) - components.protocol_end; + + if (buffer.empty()) { + buffer.append(new_scheme_with_colon); + } else { + buffer.erase(0, components.protocol_end); + buffer.insert(0, new_scheme_with_colon); + } + components.protocol_end += new_difference; + + // Update the rest of the components. + components.username_end += new_difference; + components.host_start += new_difference; + components.host_end += new_difference; + components.pathname_start += new_difference; + if (components.search_start != url_components::omitted) { + components.search_start += new_difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += new_difference; + } + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::set_scheme(std::string_view new_scheme) noexcept { + ada_log("url_aggregator::set_scheme ", new_scheme); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(new_scheme.empty() || new_scheme.back() != ':'); + // next line could overflow but unsigned arithmetic has well-defined + // overflows. + uint32_t new_difference = + uint32_t(new_scheme.size()) - components.protocol_end + 1; + + type = ada::scheme::get_scheme_type(new_scheme); + if (buffer.empty()) { + buffer.append(helpers::concat(new_scheme, ":")); + } else { + buffer.erase(0, components.protocol_end); + buffer.insert(0, helpers::concat(new_scheme, ":")); + } + components.protocol_end = uint32_t(new_scheme.size() + 1); + + // Update the rest of the components. + components.username_end += new_difference; + components.host_start += new_difference; + components.host_end += new_difference; + components.pathname_start += new_difference; + if (components.search_start != url_components::omitted) { + components.search_start += new_difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += new_difference; + } + ADA_ASSERT_TRUE(validate()); +} + +bool url_aggregator::set_protocol(const std::string_view input) { + ada_log("url_aggregator::set_protocol ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + std::string view(input); + helpers::remove_ascii_tab_or_newline(view); + if (view.empty()) { + return true; + } + + // Schemes should start with alpha values. + if (!checkers::is_alpha(view[0])) { + return false; + } + + view.append(":"); + + std::string::iterator pointer = + std::ranges::find_if_not(view, unicode::is_alnum_plus); + + if (pointer != view.end() && *pointer == ':') { + return parse_scheme_with_colon( + std::string_view(view.data(), pointer - view.begin() + 1)); + } + return false; +} + +bool url_aggregator::set_username(const std::string_view input) { + ada_log("url_aggregator::set_username '", input, "' "); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (cannot_have_credentials_or_port()) { + return false; + } + size_t idx = ada::unicode::percent_encode_index( + input, character_sets::USERINFO_PERCENT_ENCODE); + if (idx == input.size()) { + update_base_username(input); + } else { + // We only create a temporary string if we have to! + update_base_username(ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE, idx)); + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +bool url_aggregator::set_password(const std::string_view input) { + ada_log("url_aggregator::set_password '", input, "'"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (cannot_have_credentials_or_port()) { + return false; + } + size_t idx = ada::unicode::percent_encode_index( + input, character_sets::USERINFO_PERCENT_ENCODE); + if (idx == input.size()) { + update_base_password(input); + } else { + // We only create a temporary string if we have to! + update_base_password(ada::unicode::percent_encode( + input, character_sets::USERINFO_PERCENT_ENCODE, idx)); + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +bool url_aggregator::set_port(const std::string_view input) { + ada_log("url_aggregator::set_port ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (cannot_have_credentials_or_port()) { + return false; + } + std::string trimmed(input); + helpers::remove_ascii_tab_or_newline(trimmed); + if (trimmed.empty()) { + clear_port(); + return true; + } + + // Input should not start with a non-digit character. + if (!ada::unicode::is_ascii_digit(trimmed.front())) { + return false; + } + + // Revert changes if parse_port fails. + uint32_t previous_port = components.port; + parse_port(trimmed); + if (is_valid) { + return true; + } + update_base_port(previous_port); + is_valid = true; + ADA_ASSERT_TRUE(validate()); + return false; +} + +bool url_aggregator::set_pathname(const std::string_view input) { + ada_log("url_aggregator::set_pathname ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (has_opaque_path) { + return false; + } + clear_pathname(); + parse_path(input); + if (get_pathname().starts_with("//") && !has_authority() && !has_dash_dot()) { + buffer.insert(components.pathname_start, "/."); + components.pathname_start += 2; + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +ada_really_inline void url_aggregator::parse_path(std::string_view input) { + ada_log("url_aggregator::parse_path ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + std::string tmp_buffer; + std::string_view internal_input; + if (unicode::has_tabs_or_newline(input)) { + tmp_buffer = input; + // Optimization opportunity: Instead of copying and then pruning, we could + // just directly build the string from user_input. + helpers::remove_ascii_tab_or_newline(tmp_buffer); + internal_input = tmp_buffer; + } else { + internal_input = input; + } + + // If url is special, then: + if (is_special()) { + if (internal_input.empty()) { + update_base_pathname("/"); + } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) { + consume_prepared_path(internal_input.substr(1)); + } else { + consume_prepared_path(internal_input); + } + } else if (!internal_input.empty()) { + if (internal_input[0] == '/') { + consume_prepared_path(internal_input.substr(1)); + } else { + consume_prepared_path(internal_input); + } + } else { + // Non-special URLs with an empty host can have their paths erased + // Path-only URLs cannot have their paths erased + if (components.host_start == components.host_end && !has_authority()) { + update_base_pathname("/"); + } + } + ADA_ASSERT_TRUE(validate()); +} + +void url_aggregator::set_search(const std::string_view input) { + ada_log("url_aggregator::set_search ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + clear_search(); + helpers::strip_trailing_spaces_from_opaque_path(*this); + return; + } + + std::string new_value; + new_value = input[0] == '?' ? input.substr(1) : input; + helpers::remove_ascii_tab_or_newline(new_value); + + auto query_percent_encode_set = + is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE + : ada::character_sets::QUERY_PERCENT_ENCODE; + + update_base_search(new_value, query_percent_encode_set); + ADA_ASSERT_TRUE(validate()); +} + +void url_aggregator::set_hash(const std::string_view input) { + ada_log("url_aggregator::set_hash ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + if (components.hash_start != url_components::omitted) { + buffer.resize(components.hash_start); + components.hash_start = url_components::omitted; + } + helpers::strip_trailing_spaces_from_opaque_path(*this); + return; + } + + std::string new_value; + new_value = input[0] == '#' ? input.substr(1) : input; + helpers::remove_ascii_tab_or_newline(new_value); + update_unencoded_base_hash(new_value); + ADA_ASSERT_TRUE(validate()); +} + +bool url_aggregator::set_href(const std::string_view input) { + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + ada_log("url_aggregator::set_href ", input, " [", input.size(), " bytes]"); + ada::result out = ada::parse(input); + ada_log("url_aggregator::set_href, success :", out.has_value()); + + if (out) { + ada_log("url_aggregator::set_href, parsed ", out->to_string()); + // TODO: Figure out why the following line puts test to never finish. + *this = *out; + } + + return out.has_value(); +} + +ada_really_inline bool url_aggregator::parse_host(std::string_view input) { + ada_log("url_aggregator:parse_host \"", input, "\" [", input.size(), + " bytes]"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + return is_valid = false; + } // technically unnecessary. + // If input starts with U+005B ([), then: + if (input[0] == '[') { + // If input does not end with U+005D (]), validation error, return failure. + if (input.back() != ']') { + return is_valid = false; + } + ada_log("parse_host ipv6"); + + // Return the result of IPv6 parsing input with its leading U+005B ([) and + // trailing U+005D (]) removed. + input.remove_prefix(1); + input.remove_suffix(1); + return parse_ipv6(input); + } + + // If isNotSpecial is true, then return the result of opaque-host parsing + // input. + if (!is_special()) { + return parse_opaque_host(input); + } + // Let domain be the result of running UTF-8 decode without BOM on the + // percent-decoding of input. Let asciiDomain be the result of running domain + // to ASCII with domain and false. The most common case is an ASCII input, in + // which case we do not need to call the expensive 'to_ascii' if a few + // conditions are met: no '%' and no 'xn-' subsequence. + + // Often, the input does not contain any forbidden code points, and no upper + // case ASCII letter, then we can just copy it to the buffer. We want to + // optimize for such a common case. + uint8_t is_forbidden_or_upper = + unicode::contains_forbidden_domain_code_point_or_upper(input.data(), + input.size()); + // Minor optimization opportunity: + // contains_forbidden_domain_code_point_or_upper could be extend to check for + // the presence of characters that cannot appear in the ipv4 address and we + // could also check whether x and n and - are present, and so we could skip + // some of the checks below. However, the gains are likely to be small, and + // the code would be more complex. + if (is_forbidden_or_upper == 0 && + input.find("xn-") == std::string_view::npos) { + // fast path + update_base_hostname(input); + if (checkers::is_ipv4(get_hostname())) { + ada_log("parse_host fast path ipv4"); + return parse_ipv4(get_hostname(), true); + } + ada_log("parse_host fast path ", get_hostname()); + return true; + } + // We have encountered at least one forbidden code point or the input contains + // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full + // conversion. + + ada_log("parse_host calling to_ascii"); + std::optional host = std::string(get_hostname()); + is_valid = ada::unicode::to_ascii(host, input, input.find('%')); + if (!is_valid) { + ada_log("parse_host to_ascii returns false"); + return is_valid = false; + } + ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(), + " bytes]"); + + if (std::any_of(host.value().begin(), host.value().end(), + ada::unicode::is_forbidden_domain_code_point)) { + return is_valid = false; + } + + // If asciiDomain ends in a number, then return the result of IPv4 parsing + // asciiDomain. + if (checkers::is_ipv4(host.value())) { + ada_log("parse_host got ipv4 ", *host); + return parse_ipv4(host.value(), false); + } + + update_base_hostname(host.value()); + ADA_ASSERT_TRUE(validate()); + return true; +} + +template +bool url_aggregator::set_host_or_hostname(const std::string_view input) { + ada_log("url_aggregator::set_host_or_hostname ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (has_opaque_path) { + return false; + } + + std::string previous_host(get_hostname()); + uint32_t previous_port = components.port; + + size_t host_end_pos = input.find('#'); + std::string _host(input.data(), host_end_pos != std::string_view::npos + ? host_end_pos + : input.size()); + helpers::remove_ascii_tab_or_newline(_host); + std::string_view new_host(_host); + + // If url's scheme is "file", then set state to file host state, instead of + // host state. + if (type != ada::scheme::type::FILE) { + std::string_view host_view(_host.data(), _host.length()); + auto [location, found_colon] = + helpers::get_host_delimiter_location(is_special(), host_view); + + // Otherwise, if c is U+003A (:) and insideBrackets is false, then: + // Note: the 'found_colon' value is true if and only if a colon was + // encountered while not inside brackets. + if (found_colon) { + if constexpr (override_hostname) { + return false; + } + std::string_view sub_buffer = new_host.substr(location + 1); + if (!sub_buffer.empty()) { + set_port(sub_buffer); + } + } + // If url is special and host_view is the empty string, validation error, + // return failure. Otherwise, if state override is given, host_view is the + // empty string, and either url includes credentials or url's port is + // non-null, return. + else if (host_view.empty() && + (is_special() || has_credentials() || has_port())) { + return false; + } + + // Let host be the result of host parsing host_view with url is not special. + if (host_view.empty() && !is_special()) { + if (has_hostname()) { + clear_hostname(); // easy! + } else if (has_dash_dot()) { + add_authority_slashes_if_needed(); + delete_dash_dot(); + } + return true; + } + + bool succeeded = parse_host(host_view); + if (!succeeded) { + update_base_hostname(previous_host); + update_base_port(previous_port); + } else if (has_dash_dot()) { + // Should remove dash_dot from pathname + delete_dash_dot(); + } + return succeeded; + } + + size_t location = new_host.find_first_of("/\\?"); + if (location != std::string_view::npos) { + new_host.remove_suffix(new_host.length() - location); + } + + if (new_host.empty()) { + // Set url's host to the empty string. + clear_hostname(); + } else { + // Let host be the result of host parsing buffer with url is not special. + if (!parse_host(new_host)) { + update_base_hostname(previous_host); + update_base_port(previous_port); + return false; + } + + // If host is "localhost", then set host to the empty string. + if (helpers::substring(buffer, components.host_start, + components.host_end) == "localhost") { + clear_hostname(); + } + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +bool url_aggregator::set_host(const std::string_view input) { + ada_log("url_aggregator::set_host '", input, "'"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + return set_host_or_hostname(input); +} + +bool url_aggregator::set_hostname(const std::string_view input) { + ada_log("url_aggregator::set_hostname '", input, "'"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + return set_host_or_hostname(input); +} + +[[nodiscard]] std::string url_aggregator::get_origin() const noexcept { + ada_log("url_aggregator::get_origin"); + if (is_special()) { + // Return a new opaque origin. + if (type == scheme::FILE) { + return "null"; + } + + return helpers::concat(get_protocol(), "//", get_host()); + } + + if (get_protocol() == "blob:") { + std::string_view path = get_pathname(); + if (!path.empty()) { + auto out = ada::parse(path); + if (out && (out->type == scheme::HTTP || out->type == scheme::HTTPS)) { + // If pathURL's scheme is not "http" and not "https", then return a + // new opaque origin. + return helpers::concat(out->get_protocol(), "//", out->get_host()); + } + } + } + + // Return a new opaque origin. + return "null"; +} + +[[nodiscard]] std::string_view url_aggregator::get_username() const noexcept + ada_lifetime_bound { + ada_log("url_aggregator::get_username"); + if (has_non_empty_username()) { + return helpers::substring(buffer, components.protocol_end + 2, + components.username_end); + } + return ""; +} + +[[nodiscard]] std::string_view url_aggregator::get_password() const noexcept + ada_lifetime_bound { + ada_log("url_aggregator::get_password"); + if (has_non_empty_password()) { + return helpers::substring(buffer, components.username_end + 1, + components.host_start); + } + return ""; +} + +[[nodiscard]] std::string_view url_aggregator::get_port() const noexcept + ada_lifetime_bound { + ada_log("url_aggregator::get_port"); + if (components.port == url_components::omitted) { + return ""; + } + return helpers::substring(buffer, components.host_end + 1, + components.pathname_start); +} + +[[nodiscard]] std::string_view url_aggregator::get_hash() const noexcept + ada_lifetime_bound { + ada_log("url_aggregator::get_hash"); + // If this's URL's fragment is either null or the empty string, then return + // the empty string. Return U+0023 (#), followed by this's URL's fragment. + if (components.hash_start == url_components::omitted) { + return ""; + } + if (buffer.size() - components.hash_start <= 1) { + return ""; + } + return helpers::substring(buffer, components.hash_start); +} + +[[nodiscard]] std::string_view url_aggregator::get_host() const noexcept + ada_lifetime_bound { + ada_log("url_aggregator::get_host"); + // Technically, we should check if there is a hostname, but + // the code below works even if there isn't. + // if(!has_hostname()) { return ""; } + size_t start = components.host_start; + if (components.host_end > components.host_start && + buffer[components.host_start] == '@') { + start++; + } + // if we have an empty host, then the space between components.host_end and + // components.pathname_start may be occupied by /. + if (start == components.host_end) { + return {}; + } + return helpers::substring(buffer, start, components.pathname_start); +} + +[[nodiscard]] std::string_view url_aggregator::get_hostname() const noexcept + ada_lifetime_bound { + ada_log("url_aggregator::get_hostname"); + // Technically, we should check if there is a hostname, but + // the code below works even if there isn't. + // if(!has_hostname()) { return ""; } + size_t start = components.host_start; + // So host_start is not where the host begins. + if (components.host_end > components.host_start && + buffer[components.host_start] == '@') { + start++; + } + return helpers::substring(buffer, start, components.host_end); +} + +[[nodiscard]] std::string_view url_aggregator::get_search() const noexcept + ada_lifetime_bound { + ada_log("url_aggregator::get_search"); + // If this's URL's query is either null or the empty string, then return the + // empty string. Return U+003F (?), followed by this's URL's query. + if (components.search_start == url_components::omitted) { + return ""; + } + auto ending_index = uint32_t(buffer.size()); + if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + if (ending_index - components.search_start <= 1) { + return ""; + } + return helpers::substring(buffer, components.search_start, ending_index); +} + +[[nodiscard]] std::string_view url_aggregator::get_protocol() const noexcept + ada_lifetime_bound { + ada_log("url_aggregator::get_protocol"); + return helpers::substring(buffer, 0, components.protocol_end); +} + +[[nodiscard]] std::string ada::url_aggregator::to_string() const { + ada_log("url_aggregator::to_string buffer:", buffer, " [", buffer.size(), + " bytes]"); + if (!is_valid) { + return "null"; + } + + std::string answer; + auto back = std::back_insert_iterator(answer); + answer.append("{\n"); + + answer.append("\t\"buffer\":\""); + helpers::encode_json(buffer, back); + answer.append("\",\n"); + + answer.append("\t\"protocol\":\""); + helpers::encode_json(get_protocol(), back); + answer.append("\",\n"); + + if (has_credentials()) { + answer.append("\t\"username\":\""); + helpers::encode_json(get_username(), back); + answer.append("\",\n"); + answer.append("\t\"password\":\""); + helpers::encode_json(get_password(), back); + answer.append("\",\n"); + } + + answer.append("\t\"host\":\""); + helpers::encode_json(get_host(), back); + answer.append("\",\n"); + + answer.append("\t\"path\":\""); + helpers::encode_json(get_pathname(), back); + answer.append("\",\n"); + answer.append("\t\"opaque path\":"); + answer.append((has_opaque_path ? "true" : "false")); + answer.append(",\n"); + + if (components.search_start != url_components::omitted) { + answer.append("\t\"query\":\""); + helpers::encode_json(get_search(), back); + answer.append("\",\n"); + } + if (components.hash_start != url_components::omitted) { + answer.append("\t\"fragment\":\""); + helpers::encode_json(get_hash(), back); + answer.append("\",\n"); + } + + auto convert_offset_to_string = [](uint32_t offset) -> std::string { + if (offset == url_components::omitted) { + return "null"; + } else { + return std::to_string(offset); + } + }; + + answer.append("\t\"protocol_end\":"); + answer.append(convert_offset_to_string(components.protocol_end)); + answer.append(",\n"); + + answer.append("\t\"username_end\":"); + answer.append(convert_offset_to_string(components.username_end)); + answer.append(",\n"); + + answer.append("\t\"host_start\":"); + answer.append(convert_offset_to_string(components.host_start)); + answer.append(",\n"); + + answer.append("\t\"host_end\":"); + answer.append(convert_offset_to_string(components.host_end)); + answer.append(",\n"); + + answer.append("\t\"port\":"); + answer.append(convert_offset_to_string(components.port)); + answer.append(",\n"); + + answer.append("\t\"pathname_start\":"); + answer.append(convert_offset_to_string(components.pathname_start)); + answer.append(",\n"); + + answer.append("\t\"search_start\":"); + answer.append(convert_offset_to_string(components.search_start)); + answer.append(",\n"); + + answer.append("\t\"hash_start\":"); + answer.append(convert_offset_to_string(components.hash_start)); + answer.append("\n}"); + + return answer; +} + +[[nodiscard]] bool url_aggregator::has_valid_domain() const noexcept { + if (components.host_start == components.host_end) { + return false; + } + return checkers::verify_dns_length(get_hostname()); +} + +bool url_aggregator::parse_ipv4(std::string_view input, bool in_place) { + ada_log("parse_ipv4 ", input, " [", input.size(), + " bytes], overlaps with buffer: ", + helpers::overlaps(input, buffer) ? "yes" : "no"); + ADA_ASSERT_TRUE(validate()); + const bool trailing_dot = (input.back() == '.'); + if (trailing_dot) { + input.remove_suffix(1); + } + size_t digit_count{0}; + int pure_decimal_count = 0; // entries that are decimal + uint64_t ipv4{0}; + // we could unroll for better performance? + for (; (digit_count < 4) && !(input.empty()); digit_count++) { + uint32_t + segment_result{}; // If any number exceeds 32 bits, we have an error. + bool is_hex = checkers::has_hex_prefix(input); + if (is_hex && ((input.length() == 2) || + ((input.length() > 2) && (input[2] == '.')))) { + // special case + segment_result = 0; + input.remove_prefix(2); + } else { + std::from_chars_result r{}; + if (is_hex) { + ada_log("parse_ipv4 trying to parse hex number"); + r = std::from_chars(input.data() + 2, input.data() + input.size(), + segment_result, 16); + } else if ((input.length() >= 2) && input[0] == '0' && + checkers::is_digit(input[1])) { + ada_log("parse_ipv4 trying to parse octal number"); + r = std::from_chars(input.data() + 1, input.data() + input.size(), + segment_result, 8); + } else { + ada_log("parse_ipv4 trying to parse decimal number"); + pure_decimal_count++; + r = std::from_chars(input.data(), input.data() + input.size(), + segment_result, 10); + } + if (r.ec != std::errc()) { + ada_log("parse_ipv4 parsing failed"); + return is_valid = false; + } + ada_log("parse_ipv4 parsed ", segment_result); + input.remove_prefix(r.ptr - input.data()); + } + if (input.empty()) { + // We have the last value. + // At this stage, ipv4 contains digit_count*8 bits. + // So we have 32-digit_count*8 bits left. + if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) { + return is_valid = false; + } + ipv4 <<= (32 - digit_count * 8); + ipv4 |= segment_result; + goto final; + } else { + // There is more, so that the value must no be larger than 255 + // and we must have a '.'. + if ((segment_result > 255) || (input[0] != '.')) { + return is_valid = false; + } + ipv4 <<= 8; + ipv4 |= segment_result; + input.remove_prefix(1); // remove '.' + } + } + if ((digit_count != 4) || (!input.empty())) { + ada_log("parse_ipv4 found invalid (more than 4 numbers or empty) "); + return is_valid = false; + } +final: + ada_log("url_aggregator::parse_ipv4 completed ", get_href(), + " host: ", get_host()); + + // We could also check r.ptr to see where the parsing ended. + if (in_place && pure_decimal_count == 4 && !trailing_dot) { + ada_log( + "url_aggregator::parse_ipv4 completed and was already correct in the " + "buffer"); + // The original input was already all decimal and we validated it. So we + // don't need to do anything. + } else { + ada_log("url_aggregator::parse_ipv4 completed and we need to update it"); + // Optimization opportunity: Get rid of unnecessary string return in ipv4 + // serializer. + // TODO: This is likely a bug because it goes back update_base_hostname, not + // what we want to do. + update_base_hostname( + ada::serializers::ipv4(ipv4)); // We have to reserialize the address. + } + host_type = IPV4; + ADA_ASSERT_TRUE(validate()); + return true; +} + +bool url_aggregator::parse_ipv6(std::string_view input) { + // TODO: Implement in_place optimization: we know that input points + // in the buffer, so we can just check whether the buffer is already + // well formatted. + // TODO: Find a way to merge parse_ipv6 with url.cpp implementation. + ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + return is_valid = false; + } + // Let address be a new IPv6 address whose IPv6 pieces are all 0. + std::array address{}; + + // Let pieceIndex be 0. + int piece_index = 0; + + // Let compress be null. + std::optional compress{}; + + // Let pointer be a pointer for input. + std::string_view::iterator pointer = input.begin(); + + // If c is U+003A (:), then: + if (input[0] == ':') { + // If remaining does not start with U+003A (:), validation error, return + // failure. + if (input.size() == 1 || input[1] != ':') { + ada_log("parse_ipv6 starts with : but the rest does not start with :"); + return is_valid = false; + } + + // Increase pointer by 2. + pointer += 2; + + // Increase pieceIndex by 1 and then set compress to pieceIndex. + compress = ++piece_index; + } + + // While c is not the EOF code point: + while (pointer != input.end()) { + // If pieceIndex is 8, validation error, return failure. + if (piece_index == 8) { + ada_log("parse_ipv6 piece_index == 8"); + return is_valid = false; + } + + // If c is U+003A (:), then: + if (*pointer == ':') { + // If compress is non-null, validation error, return failure. + if (compress.has_value()) { + ada_log("parse_ipv6 compress is non-null"); + return is_valid = false; + } + + // Increase pointer and pieceIndex by 1, set compress to pieceIndex, and + // then continue. + pointer++; + compress = ++piece_index; + continue; + } + + // Let value and length be 0. + uint16_t value = 0, length = 0; + + // While length is less than 4 and c is an ASCII hex digit, + // set value to value times 0x10 + c interpreted as hexadecimal number, and + // increase pointer and length by 1. + while (length < 4 && pointer != input.end() && + unicode::is_ascii_hex_digit(*pointer)) { + // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int + value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer)); + pointer++; + length++; + } + + // If c is U+002E (.), then: + if (pointer != input.end() && *pointer == '.') { + // If length is 0, validation error, return failure. + if (length == 0) { + ada_log("parse_ipv6 length is 0"); + return is_valid = false; + } + + // Decrease pointer by length. + pointer -= length; + + // If pieceIndex is greater than 6, validation error, return failure. + if (piece_index > 6) { + ada_log("parse_ipv6 piece_index > 6"); + return is_valid = false; + } + + // Let numbersSeen be 0. + int numbers_seen = 0; + + // While c is not the EOF code point: + while (pointer != input.end()) { + // Let ipv4Piece be null. + std::optional ipv4_piece{}; + + // If numbersSeen is greater than 0, then: + if (numbers_seen > 0) { + // If c is a U+002E (.) and numbersSeen is less than 4, then increase + // pointer by 1. + if (*pointer == '.' && numbers_seen < 4) { + pointer++; + } else { + // Otherwise, validation error, return failure. + ada_log("parse_ipv6 Otherwise, validation error, return failure"); + return is_valid = false; + } + } + + // If c is not an ASCII digit, validation error, return failure. + if (pointer == input.end() || !checkers::is_digit(*pointer)) { + ada_log( + "parse_ipv6 If c is not an ASCII digit, validation error, return " + "failure"); + return is_valid = false; + } + + // While c is an ASCII digit: + while (pointer != input.end() && checkers::is_digit(*pointer)) { + // Let number be c interpreted as decimal number. + int number = *pointer - '0'; + + // If ipv4Piece is null, then set ipv4Piece to number. + if (!ipv4_piece.has_value()) { + ipv4_piece = number; + } + // Otherwise, if ipv4Piece is 0, validation error, return failure. + else if (ipv4_piece == 0) { + ada_log("parse_ipv6 if ipv4Piece is 0, validation error"); + return is_valid = false; + } + // Otherwise, set ipv4Piece to ipv4Piece times 10 + number. + else { + ipv4_piece = *ipv4_piece * 10 + number; + } + + // If ipv4Piece is greater than 255, validation error, return failure. + if (ipv4_piece > 255) { + ada_log("parse_ipv6 ipv4_piece > 255"); + return is_valid = false; + } + + // Increase pointer by 1. + pointer++; + } + + // Set address[pieceIndex] to address[pieceIndex] times 0x100 + + // ipv4Piece. + // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int + address[piece_index] = + uint16_t(address[piece_index] * 0x100 + *ipv4_piece); + + // Increase numbersSeen by 1. + numbers_seen++; + + // If numbersSeen is 2 or 4, then increase pieceIndex by 1. + if (numbers_seen == 2 || numbers_seen == 4) { + piece_index++; + } + } + + // If numbersSeen is not 4, validation error, return failure. + if (numbers_seen != 4) { + return is_valid = false; + } + + // Break. + break; + } + // Otherwise, if c is U+003A (:): + else if ((pointer != input.end()) && (*pointer == ':')) { + // Increase pointer by 1. + pointer++; + + // If c is the EOF code point, validation error, return failure. + if (pointer == input.end()) { + ada_log( + "parse_ipv6 If c is the EOF code point, validation error, return " + "failure"); + return is_valid = false; + } + } + // Otherwise, if c is not the EOF code point, validation error, return + // failure. + else if (pointer != input.end()) { + ada_log( + "parse_ipv6 Otherwise, if c is not the EOF code point, validation " + "error, return failure"); + return is_valid = false; + } + + // Set address[pieceIndex] to value. + address[piece_index] = value; + + // Increase pieceIndex by 1. + piece_index++; + } + + // If compress is non-null, then: + if (compress.has_value()) { + // Let swaps be pieceIndex - compress. + int swaps = piece_index - *compress; + + // Set pieceIndex to 7. + piece_index = 7; + + // While pieceIndex is not 0 and swaps is greater than 0, + // swap address[pieceIndex] with address[compress + swaps - 1], and then + // decrease both pieceIndex and swaps by 1. + while (piece_index != 0 && swaps > 0) { + std::swap(address[piece_index], address[*compress + swaps - 1]); + piece_index--; + swaps--; + } + } + // Otherwise, if compress is null and pieceIndex is not 8, validation error, + // return failure. + else if (piece_index != 8) { + ada_log( + "parse_ipv6 if compress is null and pieceIndex is not 8, validation " + "error, return failure"); + return is_valid = false; + } + // TODO: Optimization opportunity: Get rid of unnecessary string creation. + // TODO: This is likely a bug because it goes back update_base_hostname, not + // what we want to do. + update_base_hostname(ada::serializers::ipv6(address)); + ada_log("parse_ipv6 ", get_hostname()); + ADA_ASSERT_TRUE(validate()); + host_type = IPV6; + return true; +} + +bool url_aggregator::parse_opaque_host(std::string_view input) { + ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (std::any_of(input.begin(), input.end(), + ada::unicode::is_forbidden_host_code_point)) { + return is_valid = false; + } + + // Return the result of running UTF-8 percent-encode on input using the C0 + // control percent-encode set. + size_t idx = ada::unicode::percent_encode_index( + input, character_sets::C0_CONTROL_PERCENT_ENCODE); + if (idx == input.size()) { + update_base_hostname(input); + } else { + // We only create a temporary string if we need to. + update_base_hostname(ada::unicode::percent_encode( + input, character_sets::C0_CONTROL_PERCENT_ENCODE, idx)); + } + ADA_ASSERT_TRUE(validate()); + return true; +} + +[[nodiscard]] std::string url_aggregator::to_diagram() const { + if (!is_valid) { + return "invalid"; + } + std::string answer; + answer.append(buffer); + answer.append(" ["); + answer.append(std::to_string(buffer.size())); + answer.append(" bytes]"); + answer.append("\n"); + // first line + std::string line1; + line1.resize(buffer.size(), ' '); + if (components.hash_start != url_components::omitted) { + line1[components.hash_start] = '|'; + } + if (components.search_start != url_components::omitted) { + line1[components.search_start] = '|'; + } + if (components.pathname_start != buffer.size()) { + line1[components.pathname_start] = '|'; + } + if (components.host_end != buffer.size()) { + line1[components.host_end] = '|'; + } + if (components.host_start != buffer.size()) { + line1[components.host_start] = '|'; + } + if (components.username_end != buffer.size()) { + line1[components.username_end] = '|'; + } + if (components.protocol_end != buffer.size()) { + line1[components.protocol_end] = '|'; + } + answer.append(line1); + answer.append("\n"); + + std::string line2 = line1; + if (components.hash_start != url_components::omitted) { + line2[components.hash_start] = '`'; + line1[components.hash_start] = ' '; + + for (size_t i = components.hash_start + 1; i < line2.size(); i++) { + line2[i] = '-'; + } + line2.append(" hash_start"); + answer.append(line2); + answer.append("\n"); + } + + std::string line3 = line1; + if (components.search_start != url_components::omitted) { + line3[components.search_start] = '`'; + line1[components.search_start] = ' '; + + for (size_t i = components.search_start + 1; i < line3.size(); i++) { + line3[i] = '-'; + } + line3.append(" search_start "); + line3.append(std::to_string(components.search_start)); + answer.append(line3); + answer.append("\n"); + } + + std::string line4 = line1; + if (components.pathname_start != buffer.size()) { + line4[components.pathname_start] = '`'; + line1[components.pathname_start] = ' '; + for (size_t i = components.pathname_start + 1; i < line4.size(); i++) { + line4[i] = '-'; + } + line4.append(" pathname_start "); + line4.append(std::to_string(components.pathname_start)); + answer.append(line4); + answer.append("\n"); + } + + std::string line5 = line1; + if (components.host_end != buffer.size()) { + line5[components.host_end] = '`'; + line1[components.host_end] = ' '; + + for (size_t i = components.host_end + 1; i < line5.size(); i++) { + line5[i] = '-'; + } + line5.append(" host_end "); + line5.append(std::to_string(components.host_end)); + answer.append(line5); + answer.append("\n"); + } + + std::string line6 = line1; + if (components.host_start != buffer.size()) { + line6[components.host_start] = '`'; + line1[components.host_start] = ' '; + + for (size_t i = components.host_start + 1; i < line6.size(); i++) { + line6[i] = '-'; + } + line6.append(" host_start "); + line6.append(std::to_string(components.host_start)); + answer.append(line6); + answer.append("\n"); + } + + std::string line7 = line1; + if (components.username_end != buffer.size()) { + line7[components.username_end] = '`'; + line1[components.username_end] = ' '; + + for (size_t i = components.username_end + 1; i < line7.size(); i++) { + line7[i] = '-'; + } + line7.append(" username_end "); + line7.append(std::to_string(components.username_end)); + answer.append(line7); + answer.append("\n"); + } + + std::string line8 = line1; + if (components.protocol_end != buffer.size()) { + line8[components.protocol_end] = '`'; + line1[components.protocol_end] = ' '; + + for (size_t i = components.protocol_end + 1; i < line8.size(); i++) { + line8[i] = '-'; + } + line8.append(" protocol_end "); + line8.append(std::to_string(components.protocol_end)); + answer.append(line8); + answer.append("\n"); + } + + if (components.hash_start == url_components::omitted) { + answer.append("note: hash omitted\n"); + } + if (components.search_start == url_components::omitted) { + answer.append("note: search omitted\n"); + } + if (components.protocol_end > buffer.size()) { + answer.append("warning: protocol_end overflows\n"); + } + if (components.username_end > buffer.size()) { + answer.append("warning: username_end overflows\n"); + } + if (components.host_start > buffer.size()) { + answer.append("warning: host_start overflows\n"); + } + if (components.host_end > buffer.size()) { + answer.append("warning: host_end overflows\n"); + } + if (components.pathname_start > buffer.size()) { + answer.append("warning: pathname_start overflows\n"); + } + return answer; +} + +void url_aggregator::delete_dash_dot() { + ada_log("url_aggregator::delete_dash_dot"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(has_dash_dot()); + buffer.erase(components.host_end, 2); + components.pathname_start -= 2; + if (components.search_start != url_components::omitted) { + components.search_start -= 2; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= 2; + } + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!has_dash_dot()); +} + +inline void url_aggregator::consume_prepared_path(std::string_view input) { + ada_log("url_aggregator::consume_prepared_path ", input); + /*** + * This is largely duplicated code from helpers::parse_prepared_path, which is + * unfortunate. This particular function is nearly identical, except that it + * is a method on url_aggregator. The idea is that the trivial path (which is + * very common) merely appends to the buffer. This is the same trivial path as + * with helpers::parse_prepared_path, except that we have the additional check + * for is_at_path(). Otherwise, we grab a copy of the current path and we + * modify it, and then insert it back into the buffer. + */ + uint8_t accumulator = checkers::path_signature(input); + // Let us first detect a trivial case. + // If it is special, we check that we have no dot, no %, no \ and no + // character needing percent encoding. Otherwise, we check that we have no %, + // no dot, and no character needing percent encoding. + constexpr uint8_t need_encoding = 1; + constexpr uint8_t backslash_char = 2; + constexpr uint8_t dot_char = 4; + constexpr uint8_t percent_char = 8; + bool special = type != ada::scheme::NOT_SPECIAL; + bool may_need_slow_file_handling = (type == ada::scheme::type::FILE && + checkers::is_windows_drive_letter(input)); + bool trivial_path = + (special ? (accumulator == 0) + : ((accumulator & (need_encoding | dot_char | percent_char)) == + 0)) && + (!may_need_slow_file_handling); + if (accumulator == dot_char && !may_need_slow_file_handling) { + // '4' means that we have at least one dot, but nothing that requires + // percent encoding or decoding. The only part that is not trivial is + // that we may have single dots and double dots path segments. + // If we have such segments, then we either have a path that begins + // with '.' (easy to check), or we have the sequence './'. + // Note: input cannot be empty, it must at least contain one character ('.') + // Note: we know that '\' is not present. + if (input[0] != '.') { + size_t slashdot = input.find("/."); + if (slashdot == std::string_view::npos) { // common case + trivial_path = true; + } else { // uncommon + // only three cases matter: /./, /.. or a final / + trivial_path = + !(slashdot + 2 == input.size() || input[slashdot + 2] == '.' || + input[slashdot + 2] == '/'); + } + } + } + if (trivial_path && is_at_path()) { + ada_log("parse_path trivial"); + buffer += '/'; + buffer += input; + return; + } + std::string path = std::string(get_pathname()); + // We are going to need to look a bit at the path, but let us see if we can + // ignore percent encoding *and* backslashes *and* percent characters. + // Except for the trivial case, this is likely to capture 99% of paths out + // there. + bool fast_path = + (special && + (accumulator & (need_encoding | backslash_char | percent_char)) == 0) && + (type != ada::scheme::type::FILE); + if (fast_path) { + ada_log("parse_prepared_path fast"); + // Here we don't need to worry about \ or percent encoding. + // We also do not have a file protocol. We might have dots, however, + // but dots must as appear as '.', and they cannot be encoded because + // the symbol '%' is not present. + size_t previous_location = 0; // We start at 0. + do { + size_t new_location = input.find('/', previous_location); + // std::string_view path_view = input; + // We process the last segment separately: + if (new_location == std::string_view::npos) { + std::string_view path_view = input.substr(previous_location); + if (path_view == "..") { // The path ends with .. + // e.g., if you receive ".." with an empty path, you go to "/". + if (path.empty()) { + path = '/'; + update_base_pathname(path); + return; + } + // Fast case where we have nothing to do: + if (path.back() == '/') { + update_base_pathname(path); + return; + } + // If you have the path "/joe/myfriend", + // then you delete 'myfriend'. + path.resize(path.rfind('/') + 1); + update_base_pathname(path); + return; + } + path += '/'; + if (path_view != ".") { + path.append(path_view); + } + update_base_pathname(path); + return; + } else { + // This is a non-final segment. + std::string_view path_view = + input.substr(previous_location, new_location - previous_location); + previous_location = new_location + 1; + if (path_view == "..") { + size_t last_delimiter = path.rfind('/'); + if (last_delimiter != std::string::npos) { + path.erase(last_delimiter); + } + } else if (path_view != ".") { + path += '/'; + path.append(path_view); + } + } + } while (true); + } else { + ada_log("parse_path slow"); + // we have reached the general case + bool needs_percent_encoding = (accumulator & 1); + std::string path_buffer_tmp; + do { + size_t location = (special && (accumulator & 2)) + ? input.find_first_of("/\\") + : input.find('/'); + std::string_view path_view = input; + if (location != std::string_view::npos) { + path_view.remove_suffix(path_view.size() - location); + input.remove_prefix(location + 1); + } + // path_buffer is either path_view or it might point at a percent encoded + // temporary string. + std::string_view path_buffer = + (needs_percent_encoding && + ada::unicode::percent_encode( + path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp)) + ? path_buffer_tmp + : path_view; + if (unicode::is_double_dot_path_segment(path_buffer)) { + if ((helpers::shorten_path(path, type) || special) && + location == std::string_view::npos) { + path += '/'; + } + } else if (unicode::is_single_dot_path_segment(path_buffer) && + (location == std::string_view::npos)) { + path += '/'; + } + // Otherwise, if path_buffer is not a single-dot path segment, then: + else if (!unicode::is_single_dot_path_segment(path_buffer)) { + // If url's scheme is "file", url's path is empty, and path_buffer is a + // Windows drive letter, then replace the second code point in + // path_buffer with U+003A (:). + if (type == ada::scheme::type::FILE && path.empty() && + checkers::is_windows_drive_letter(path_buffer)) { + path += '/'; + path += path_buffer[0]; + path += ':'; + path_buffer.remove_prefix(2); + path.append(path_buffer); + } else { + // Append path_buffer to url's path. + path += '/'; + path.append(path_buffer); + } + } + if (location == std::string_view::npos) { + update_base_pathname(path); + return; + } + } while (true); + } +} +} // namespace ada +/* end file src/url_aggregator.cpp */ +/* begin file src/url_pattern.cpp */ + +#include +#include +#include + +namespace ada { + +tl::expected url_pattern_init::process( + url_pattern_init init, std::string_view type, + std::optional protocol, + std::optional username, + std::optional password, + std::optional hostname, + std::optional port, + std::optional pathname, + std::optional search, + std::optional hash) { + // Let result be the result of creating a new URLPatternInit. + auto result = url_pattern_init{}; + + // If protocol is not null, set result["protocol"] to protocol. + if (protocol.has_value()) result.protocol = *protocol; + + // If username is not null, set result["username"] to username. + if (username.has_value()) result.username = *username; + + // If password is not null, set result["password"] to password. + if (password.has_value()) result.password = *password; + + // If hostname is not null, set result["hostname"] to hostname. + if (hostname.has_value()) result.hostname = *hostname; + + // If port is not null, set result["port"] to port. + if (port.has_value()) result.port = *port; + + // If pathname is not null, set result["pathname"] to pathname. + if (pathname.has_value()) result.pathname = *pathname; + + // If search is not null, set result["search"] to search. + if (search.has_value()) result.search = *search; + + // If hash is not null, set result["hash"] to hash. + if (hash.has_value()) result.hash = *hash; + + // Let baseURL be null. + std::optional base_url{}; + + // If init["baseURL"] exists: + if (init.base_url.has_value()) { + // Set baseURL to the result of parsing init["baseURL"]. + auto parsing_result = ada::parse(*init.base_url); + // If baseURL is failure, then throw a TypeError. + if (!parsing_result) { + return tl::unexpected(errors::type_error); + } + base_url = std::move(*parsing_result); + + // If init["protocol"] does not exist, then set result["protocol"] to the + // result of processing a base URL string given baseURL’s scheme and type. + if (!init.protocol.has_value()) { + ADA_ASSERT_TRUE(base_url.has_value()); + std::string_view base_url_protocol = base_url->get_protocol(); + if (base_url_protocol.ends_with(":")) base_url_protocol.remove_suffix(1); + result.protocol = + url_pattern_helpers::process_base_url_string(base_url_protocol, type); + } + + // If type is not "pattern" and init contains none of "protocol", + // "hostname", "port" and "username", then set result["username"] to the + // result of processing a base URL string given baseURL’s username and type. + if (type != "pattern" && !init.protocol && !init.hostname && !init.port && + !init.username) { + result.username = url_pattern_helpers::process_base_url_string( + base_url->get_username(), type); + } + + // TODO: Optimization opportunity: Merge this with the previous check. + // If type is not "pattern" and init contains none of "protocol", + // "hostname", "port", "username" and "password", then set + // result["password"] to the result of processing a base URL string given + // baseURL’s password and type. + if (type != "pattern" && !init.protocol && !init.hostname && !init.port && + !init.username && !init.password) { + result.password = url_pattern_helpers::process_base_url_string( + base_url->get_password(), type); + } + + // If init contains neither "protocol" nor "hostname", then: + if (!init.protocol && !init.hostname) { + // Let baseHost be baseURL’s host. + // If baseHost is null, then set baseHost to the empty string. + auto base_host = base_url->get_hostname(); + // Set result["hostname"] to the result of processing a base URL string + // given baseHost and type. + result.hostname = + url_pattern_helpers::process_base_url_string(base_host, type); + } + + // If init contains none of "protocol", "hostname", and "port", then: + if (!init.protocol && !init.hostname && !init.port) { + // If baseURL’s port is null, then set result["port"] to the empty string. + // Otherwise, set result["port"] to baseURL’s port, serialized. + result.port = base_url->get_port(); + } + + // If init contains none of "protocol", "hostname", "port", and "pathname", + // then set result["pathname"] to the result of processing a base URL string + // given the result of URL path serializing baseURL and type. + if (!init.protocol && !init.hostname && !init.port && !init.pathname) { + result.pathname = url_pattern_helpers::process_base_url_string( + base_url->get_pathname(), type); + } + + // If init contains none of "protocol", "hostname", "port", "pathname", and + // "search", then: + if (!init.protocol && !init.hostname && !init.port && !init.pathname && + !init.search) { + // Let baseQuery be baseURL’s query. + // Set result["search"] to the result of processing a base URL string + // given baseQuery and type. + result.search = url_pattern_helpers::process_base_url_string( + base_url->get_search(), type); + } + + // If init contains none of "protocol", "hostname", "port", "pathname", + // "search", and "hash", then: + if (!init.protocol && !init.hostname && !init.port && !init.pathname && + !init.search && !init.hash) { + // Let baseFragment be baseURL’s fragment. + // Set result["hash"] to the result of processing a base URL string given + // baseFragment and type. + result.hash = url_pattern_helpers::process_base_url_string( + base_url->get_hash(), type); + } + } + + // If init["protocol"] exists, then set result["protocol"] to the result of + // process protocol for init given init["protocol"] and type. + if (init.protocol) { + auto process_result = process_protocol(*init.protocol, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.protocol = std::move(*process_result); + } + + // If init["username"] exists, then set result["username"] to the result of + // process username for init given init["username"] and type. + if (init.username.has_value()) { + auto process_result = process_username(*init.username, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.username = std::move(*process_result); + } + + // If init["password"] exists, then set result["password"] to the result of + // process password for init given init["password"] and type. + if (init.password.has_value()) { + auto process_result = process_password(*init.password, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.password = std::move(*process_result); + } + + // If init["hostname"] exists, then set result["hostname"] to the result of + // process hostname for init given init["hostname"] and type. + if (init.hostname.has_value()) { + auto process_result = process_hostname(*init.hostname, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.hostname = std::move(*process_result); + } + + // If init["port"] exists, then set result["port"] to the result of process + // port for init given init["port"], result["protocol"], and type. + if (init.port) { + auto process_result = + process_port(*init.port, result.protocol.value_or("fake"), type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.port = std::move(*process_result); + } + + // If init["pathname"] exists: + if (init.pathname.has_value()) { + // Set result["pathname"] to init["pathname"]. + result.pathname = init.pathname; + + // If the following are all true: + // - baseURL is not null; + // - baseURL has an opaque path; and + // - the result of running is an absolute pathname given result["pathname"] + // and type is false, + if (base_url && !base_url->has_opaque_path && + !url_pattern_helpers::is_absolute_pathname(*result.pathname, type)) { + // Let baseURLPath be the result of running process a base URL string + // given the result of URL path serializing baseURL and type. + std::string base_url_path = url_pattern_helpers::process_base_url_string( + base_url->get_pathname(), type); + + // Let slash index be the index of the last U+002F (/) code point found in + // baseURLPath, interpreted as a sequence of code points, or null if there + // are no instances of the code point. + auto slash_index = base_url_path.find_last_of('/'); + + // If slash index is not null: + if (slash_index != std::string::npos) { + // Let new pathname be the code point substring from 0 to slash index + + // 1 within baseURLPath. + std::string new_pathname = base_url_path.substr(0, slash_index + 1); + // Append result["pathname"] to the end of new pathname. + ADA_ASSERT_TRUE(result.pathname.has_value()); + new_pathname.append(result.pathname.value()); + // Set result["pathname"] to new pathname. + result.pathname = std::move(new_pathname); + } + } + + // Set result["pathname"] to the result of process pathname for init given + // result["pathname"], result["protocol"], and type. + auto pathname_processing_result = + process_pathname(*result.pathname, result.protocol.value_or(""), type); + if (!pathname_processing_result) { + return tl::unexpected(pathname_processing_result.error()); + } + result.pathname = std::move(*pathname_processing_result); + } + + // If init["search"] exists then set result["search"] to the result of process + // search for init given init["search"] and type. + if (init.search) { + auto process_result = process_search(*init.search, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.search = std::move(*process_result); + } + + // If init["hash"] exists then set result["hash"] to the result of process + // hash for init given init["hash"] and type. + if (init.hash) { + auto process_result = process_hash(*init.hash, type); + if (!process_result) { + return tl::unexpected(process_result.error()); + } + result.hash = std::move(*process_result); + } + // Return result. + return result; +} + +tl::expected url_pattern_init::process_protocol( + std::string_view value, std::string_view type) { + ada_log("process_protocol=", value, " [", type, "]"); + // Let strippedValue be the given value with a single trailing U+003A (:) + // removed, if any. + if (value.ends_with(":")) { + value.remove_suffix(1); + } + // If type is "pattern" then return strippedValue. + if (type == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a protocol given strippedValue. + return url_pattern_helpers::canonicalize_protocol(value); +} + +tl::expected url_pattern_init::process_username( + std::string_view value, std::string_view type) { + // If type is "pattern" then return value. + if (type == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a username given value. + return url_pattern_helpers::canonicalize_username(value); +} + +tl::expected url_pattern_init::process_password( + std::string_view value, std::string_view type) { + // If type is "pattern" then return value. + if (type == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a password given value. + return url_pattern_helpers::canonicalize_password(value); +} + +tl::expected url_pattern_init::process_hostname( + std::string_view value, std::string_view type) { + ada_log("process_hostname value=", value, " type=", type); + // If type is "pattern" then return value. + if (type == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a hostname given value. + return url_pattern_helpers::canonicalize_hostname(value); +} + +tl::expected url_pattern_init::process_port( + std::string_view port, std::string_view protocol, std::string_view type) { + // If type is "pattern" then return portValue. + if (type == "pattern") { + return std::string(port); + } + // Return the result of running canonicalize a port given portValue and + // protocolValue. + return url_pattern_helpers::canonicalize_port_with_protocol(port, protocol); +} + +tl::expected url_pattern_init::process_pathname( + std::string_view value, std::string_view protocol, std::string_view type) { + // If type is "pattern" then return pathnameValue. + if (type == "pattern") { + return std::string(value); + } + + // If protocolValue is a special scheme or the empty string, then return the + // result of running canonicalize a pathname given pathnameValue. + if (protocol.empty() || scheme::is_special(protocol)) { + return url_pattern_helpers::canonicalize_pathname(value); + } + + // Return the result of running canonicalize an opaque pathname given + // pathnameValue. + return url_pattern_helpers::canonicalize_opaque_pathname(value); +} + +tl::expected url_pattern_init::process_search( + std::string_view value, std::string_view type) { + // Let strippedValue be the given value with a single leading U+003F (?) + // removed, if any. + if (value.starts_with("?")) { + value.remove_prefix(1); + } + ADA_ASSERT_TRUE(!value.starts_with("?")); + // If type is "pattern" then return strippedValue. + if (type == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a search given strippedValue. + return url_pattern_helpers::canonicalize_search(value); +} + +tl::expected url_pattern_init::process_hash( + std::string_view value, std::string_view type) { + // Let strippedValue be the given value with a single leading U+0023 (#) + // removed, if any. + if (value.starts_with("#")) { + value.remove_prefix(1); + } + ADA_ASSERT_TRUE(!value.starts_with("#")); + // If type is "pattern" then return strippedValue. + if (type == "pattern") { + return std::string(value); + } + // Return the result of running canonicalize a hash given strippedValue. + return url_pattern_helpers::canonicalize_hash(value); +} + +} // namespace ada +/* end file src/url_pattern.cpp */ +/* begin file src/url_pattern_helpers.cpp */ + +#include +#include +#include + +namespace ada::url_pattern_helpers { + +std::tuple> +generate_regular_expression_and_name_list( + const std::vector& part_list, + url_pattern_compile_component_options options) { + // Let result be "^" + std::string result = "^"; + + // Let name list be a new list + std::vector name_list{}; + const std::string full_wildcard_regexp_value = ".*"; + + // For each part of part list: + for (const url_pattern_part& part : part_list) { + // If part's type is "fixed-text": + if (part.type == url_pattern_part_type::FIXED_TEXT) { + // If part's modifier is "none" + if (part.modifier == url_pattern_part_modifier::none) { + // Append the result of running escape a regexp string given part's + // value + result += escape_regexp_string(part.value); + } else { + // A "fixed-text" part with a modifier uses a non capturing group + // (?:) + // Append "(?:" to the end of result. + result.append("(?:"); + // Append the result of running escape a regexp string given part’s + // value to the end of result. + result.append(escape_regexp_string(part.value)); + // Append ")" to the end of result. + result.append(")"); + // Append the result of running convert a modifier to a string given + // part’s modifier to the end of result. + result.append(convert_modifier_to_string(part.modifier)); + } + continue; + } + + // Assert: part's name is not the empty string + ADA_ASSERT_TRUE(!part.name.empty()); + + // Append part's name to name list + name_list.push_back(part.name); + + // Let regexp value be part's value + std::string regexp_value = part.value; + + // If part's type is "segment-wildcard" + if (part.type == url_pattern_part_type::SEGMENT_WILDCARD) { + // then set regexp value to the result of running generate a segment + // wildcard regexp given options. + regexp_value = generate_segment_wildcard_regexp(options); + } + // Otherwise if part's type is "full-wildcard" + else if (part.type == url_pattern_part_type::FULL_WILDCARD) { + // then set regexp value to full wildcard regexp value. + regexp_value = full_wildcard_regexp_value; + } + + // If part's prefix is the empty string and part's suffix is the empty + // string + if (part.prefix.empty() && part.suffix.empty()) { + // If part's modifier is "none" or "optional" + if (part.modifier == url_pattern_part_modifier::none || + part.modifier == url_pattern_part_modifier::optional) { + // () + result += "(" + regexp_value + ")" + + convert_modifier_to_string(part.modifier); + } else { + // ((?:)) + result += "((?:" + regexp_value + ")" + + convert_modifier_to_string(part.modifier) + ")"; + } + continue; + } + + // If part's modifier is "none" or "optional" + if (part.modifier == url_pattern_part_modifier::none || + part.modifier == url_pattern_part_modifier::optional) { + // (?:()) + result += "(?:" + escape_regexp_string(part.prefix) + "(" + regexp_value + + ")" + escape_regexp_string(part.suffix) + ")" + + convert_modifier_to_string(part.modifier); + continue; + } + + // Assert: part's modifier is "zero-or-more" or "one-or-more" + ADA_ASSERT_TRUE(part.modifier == url_pattern_part_modifier::zero_or_more || + part.modifier == url_pattern_part_modifier::one_or_more); + + // Assert: part's prefix is not the empty string or part's suffix is not the + // empty string + ADA_ASSERT_TRUE(!part.prefix.empty() || !part.suffix.empty()); + + // (?:((?:)(?:(?:))*))? + // Append "(?:" to the end of result. + result.append("(?:"); + // Append the result of running escape a regexp string given part’s prefix + // to the end of result. + result.append(escape_regexp_string(part.prefix)); + // Append "((?:" to the end of result. + result.append("((?:"); + // Append regexp value to the end of result. + result.append(regexp_value); + // Append ")(?:" to the end of result. + result.append(")(?:"); + // Append the result of running escape a regexp string given part’s suffix + // to the end of result. + result.append(escape_regexp_string(part.suffix)); + // Append the result of running escape a regexp string given part’s prefix + // to the end of result. + result.append(escape_regexp_string(part.prefix)); + // Append "(?:" to the end of result. + result.append("(?:"); + // Append regexp value to the end of result. + result.append(regexp_value); + // Append "))*)" to the end of result. + result.append("))*)"); + // Append the result of running escape a regexp string given part’s suffix + // to the end of result. + result.append(escape_regexp_string(part.suffix)); + // Append ")" to the end of result. + result.append(")"); + + // If part's modifier is "zero-or-more" then append "?" to the end of result + if (part.modifier == url_pattern_part_modifier::zero_or_more) { + result += "?"; + } + } + + // Append "$" to the end of result + result += "$"; + + // Return (result, name list) + return {result, name_list}; +} + +bool is_ipv6_address(std::string_view input) noexcept { + // If input’s code point length is less than 2, then return false. + if (input.size() < 2) return false; + + // Let input code points be input interpreted as a list of code points. + // If input code points[0] is U+005B ([), then return true. + if (input.front() == '[') return true; + // If input code points[0] is U+007B ({) and input code points[1] is U+005B + // ([), then return true. + if (input.starts_with("{[")) return true; + // If input code points[0] is U+005C (\) and input code points[1] is U+005B + // ([), then return true. + return input.starts_with("\\["); +} + +std::string convert_modifier_to_string(url_pattern_part_modifier modifier) { + // TODO: Optimize this. + switch (modifier) { + // If modifier is "zero-or-more", then return "*". + case url_pattern_part_modifier::zero_or_more: + return "*"; + // If modifier is "optional", then return "?". + case url_pattern_part_modifier::optional: + return "?"; + // If modifier is "one-or-more", then return "+". + case url_pattern_part_modifier::one_or_more: + return "+"; + // Return the empty string. + default: + return ""; + } +} + +std::string generate_segment_wildcard_regexp( + url_pattern_compile_component_options options) { + // Let result be "[^". + std::string result = "[^"; + // Append the result of running escape a regexp string given options’s + // delimiter code point to the end of result. + result.append(escape_regexp_string(options.get_delimiter())); + // Append "]+?" to the end of result. + result.append("]+?"); + // Return result. + ada_log("generate_segment_wildcard_regexp result: ", result); + return result; +} + +tl::expected canonicalize_protocol( + std::string_view input) { + ada_log("canonicalize_protocol called with input=", input); + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + + // IMPORTANT: Deviation from the spec. We remove the trailing ':' here. + if (input.ends_with(":")) { + input.remove_suffix(1); + } + + // Let dummyURL be a new URL record. + // Let parseResult be the result of running the basic URL parser given value + // followed by "://dummy.test", with dummyURL as url. + if (auto dummy_url = ada::parse( + std::string(input) + "://dummy.test", nullptr)) { + // IMPORTANT: Deviation from the spec. We remove the trailing ':' here. + // Since URL parser always return protocols ending with `:` + auto protocol = dummy_url->get_protocol(); + protocol.remove_suffix(1); + return std::string(protocol); + } + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); +} + +tl::expected canonicalize_username( + std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Let dummyURL be a new URL record. + auto url = ada::parse("fake://dummy.test", nullptr); + ADA_ASSERT_TRUE(url.has_value()); + // Set the username given dummyURL and value. + if (!url->set_username(input)) { + return tl::unexpected(errors::type_error); + } + // Return dummyURL’s username. + return std::string(url->get_username()); +} + +tl::expected canonicalize_password( + std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Let dummyURL be a new URL record. + // Set the password given dummyURL and value. + auto url = ada::parse("fake://dummy.test", nullptr); + + ADA_ASSERT_TRUE(url.has_value()); + if (!url->set_password(input)) { + return tl::unexpected(errors::type_error); + } + // Return dummyURL’s password. + return std::string(url->get_password()); +} + +tl::expected canonicalize_hostname( + std::string_view input) { + ada_log("canonicalize_hostname input=", input); + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Let dummyURL be a new URL record. + // Let parseResult be the result of running the basic URL parser given value + // with dummyURL as url and hostname state as state override. + + // IMPORTANT: The protocol needs to be a special protocol, otherwise the + // hostname will not be converted using IDNA. + auto url = ada::parse("https://dummy.test", nullptr); + ADA_ASSERT_TRUE(url); + // if (!isValidHostnameInput(hostname)) return kj::none; + if (!url->set_hostname(input)) { + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); + } + // Return dummyURL’s host, serialized, or empty string if it is null. + return std::string(url->get_hostname()); +} + +tl::expected canonicalize_ipv6_hostname( + std::string_view input) { + ada_log("canonicalize_ipv6_hostname input=", input); + // TODO: Optimization opportunity: Use lookup table to speed up checking + if (std::ranges::any_of(input, [](char c) { + return c != '[' && c != ']' && c != ':' && + !unicode::is_ascii_hex_digit(c); + })) { + return tl::unexpected(errors::type_error); + } + // Append the result of running ASCII lowercase given code point to the end of + // result. + auto hostname = std::string(input); + unicode::to_lower_ascii(hostname.data(), hostname.size()); + return hostname; +} + +tl::expected canonicalize_port( + std::string_view port_value) { + // If portValue is the empty string, return portValue. + if (port_value.empty()) [[unlikely]] { + return ""; + } + // Let dummyURL be a new URL record. + // If protocolValue was given, then set dummyURL’s scheme to protocolValue. + // Let parseResult be the result of running basic URL parser given portValue + // with dummyURL as url and port state as state override. + auto url = ada::parse("fake://dummy.test", nullptr); + ADA_ASSERT_TRUE(url); + if (url->set_port(port_value)) { + // Return dummyURL’s port, serialized, or empty string if it is null. + return std::string(url->get_port()); + } + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); +} + +tl::expected canonicalize_port_with_protocol( + std::string_view port_value, std::string_view protocol) { + // If portValue is the empty string, return portValue. + if (port_value.empty()) [[unlikely]] { + return ""; + } + + // TODO: Remove this + // We have an empty protocol because get_protocol() returns an empty string + // We should handle this in the caller rather than here. + if (protocol.empty()) { + protocol = "fake"; + } else if (protocol.ends_with(":")) { + protocol.remove_suffix(1); + } + // Let dummyURL be a new URL record. + // If protocolValue was given, then set dummyURL’s scheme to protocolValue. + // Let parseResult be the result of running basic URL parser given portValue + // with dummyURL as url and port state as state override. + auto url = ada::parse(std::string(protocol) + "://dummy.test", + nullptr); + // TODO: Remove has_port() check. + // This is actually a bug with url parser where set_port() returns true for + // "invalid80" port value. + if (url && url->set_port(port_value) && url->has_port()) { + // Return dummyURL’s port, serialized, or empty string if it is null. + return std::string(url->get_port()); + } + // TODO: Remove this once the previous has_port() check is removed. + if (url) { + if (scheme::is_special(protocol) && url->get_port().empty()) { + return ""; + } + } + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); +} + +tl::expected canonicalize_pathname( + std::string_view input) { + // If value is the empty string, then return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Let leading slash be true if the first code point in value is U+002F (/) + // and otherwise false. + const bool leading_slash = input.starts_with("/"); + // Let modified value be "/-" if leading slash is false and otherwise the + // empty string. + const auto modified_value = leading_slash ? "" : "/-"; + const auto full_url = + std::string("fake://fake-url") + modified_value + std::string(input); + if (auto url = ada::parse(full_url, nullptr)) { + const auto pathname = url->get_pathname(); + // If leading slash is false, then set result to the code point substring + // from 2 to the end of the string within result. + return leading_slash ? std::string(pathname) + : std::string(pathname.substr(2)); + } + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); +} + +tl::expected canonicalize_opaque_pathname( + std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Let dummyURL be a new URL record. + // Set dummyURL’s path to the empty string. + // Let parseResult be the result of running URL parsing given value with + // dummyURL as url and opaque path state as state override. + if (auto url = + ada::parse("fake:" + std::string(input), nullptr)) { + // Return the result of URL path serializing dummyURL. + return std::string(url->get_pathname()); + } + // If parseResult is failure, then throw a TypeError. + return tl::unexpected(errors::type_error); +} + +tl::expected canonicalize_search(std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Let dummyURL be a new URL record. + // Set dummyURL’s query to the empty string. + // Let parseResult be the result of running basic URL parser given value with + // dummyURL as url and query state as state override. + auto url = ada::parse("fake://dummy.test", nullptr); + ADA_ASSERT_TRUE(url.has_value()); + url->set_search(input); + if (url->has_search()) { + const auto search = url->get_search(); + return std::string(search.substr(1)); + } + return tl::unexpected(errors::type_error); +} + +tl::expected canonicalize_hash(std::string_view input) { + // If value is the empty string, return value. + if (input.empty()) [[unlikely]] { + return ""; + } + // Let dummyURL be a new URL record. + // Set dummyURL’s fragment to the empty string. + // Let parseResult be the result of running basic URL parser given value with + // dummyURL as url and fragment state as state override. + auto url = ada::parse("fake://dummy.test", nullptr); + ADA_ASSERT_TRUE(url.has_value()); + url->set_hash(input); + // Return dummyURL’s fragment. + if (url->has_hash()) { + const auto hash = url->get_hash(); + return std::string(hash.substr(1)); + } + return tl::unexpected(errors::type_error); +} + +tl::expected, errors> tokenize(std::string_view input, + token_policy policy) { + ada_log("tokenize input: ", input); + // Let tokenizer be a new tokenizer. + // Set tokenizer’s input to input. + // Set tokenizer’s policy to policy. + auto tokenizer = Tokenizer(input, policy); + // While tokenizer’s index is less than tokenizer’s input's code point length: + while (tokenizer.index < tokenizer.input.size()) { + // Run seek and get the next code point given tokenizer and tokenizer’s + // index. + tokenizer.seek_and_get_next_code_point(tokenizer.index); + + // If tokenizer’s code point is U+002A (*): + if (tokenizer.code_point == '*') { + // Run add a token with default position and length given tokenizer and + // "asterisk". + tokenizer.add_token_with_defaults(token_type::ASTERISK); + ada_log("add ASTERISK token"); + // Continue. + continue; + } + + // If tokenizer’s code point is U+002B (+) or U+003F (?): + if (tokenizer.code_point == '+' || tokenizer.code_point == '?') { + // Run add a token with default position and length given tokenizer and + // "other-modifier". + tokenizer.add_token_with_defaults(token_type::OTHER_MODIFIER); + // Continue. + continue; + } + + // If tokenizer’s code point is U+005C (\): + if (tokenizer.code_point == '\\') { + // If tokenizer’s index is equal to tokenizer’s input's code point length + // − 1: + if (tokenizer.index == tokenizer.input.size() - 1) { + // Run process a tokenizing error given tokenizer, tokenizer’s next + // index, and tokenizer’s index. + if (auto error = tokenizer.process_tokenizing_error( + tokenizer.next_index, tokenizer.index)) { + ada_log("process_tokenizing_error failed"); + return tl::unexpected(*error); + } + continue; + } + + // Let escaped index be tokenizer’s next index. + auto escaped_index = tokenizer.next_index; + // Run get the next code point given tokenizer. + tokenizer.get_next_code_point(); + // Run add a token with default length given tokenizer, "escaped-char", + // tokenizer’s next index, and escaped index. + tokenizer.add_token_with_default_length( + token_type::ESCAPED_CHAR, tokenizer.next_index, escaped_index); + ada_log("add ESCAPED_CHAR token on next_index ", tokenizer.next_index, + " with escaped index ", escaped_index); + // Continue. + continue; + } + + // If tokenizer’s code point is U+007B ({): + if (tokenizer.code_point == '{') { + // Run add a token with default position and length given tokenizer and + // "open". + tokenizer.add_token_with_defaults(token_type::OPEN); + ada_log("add OPEN token"); + continue; + } + + // If tokenizer’s code point is U+007D (}): + if (tokenizer.code_point == '}') { + // Run add a token with default position and length given tokenizer and + // "close". + tokenizer.add_token_with_defaults(token_type::CLOSE); + ada_log("add CLOSE token"); + continue; + } + + // If tokenizer’s code point is U+003A (:): + if (tokenizer.code_point == ':') { + // Let name position be tokenizer’s next index. + auto name_position = tokenizer.next_index; + // Let name start be name position. + auto name_start = name_position; + // While name position is less than tokenizer’s input's code point length: + while (name_position < tokenizer.input.size()) { + // Run seek and get the next code point given tokenizer and name + // position. + tokenizer.seek_and_get_next_code_point(name_position); + // Let first code point be true if name position equals name start and + // false otherwise. + bool first_code_point = name_position == name_start; + // Let valid code point be the result of running is a valid name code + // point given tokenizer’s code point and first code point. + auto valid_code_point = + idna::valid_name_code_point(tokenizer.code_point, first_code_point); + ada_log("tokenizer.code_point=", uint32_t(tokenizer.code_point), + " first_code_point=", first_code_point, + " valid_code_point=", valid_code_point); + // If valid code point is false break. + if (!valid_code_point) break; + // Set name position to tokenizer’s next index. + name_position = tokenizer.next_index; + } + + // If name position is less than or equal to name start: + if (name_position <= name_start) { + // Run process a tokenizing error given tokenizer, name start, and + // tokenizer’s index. + if (auto error = tokenizer.process_tokenizing_error(name_start, + tokenizer.index)) { + ada_log("process_tokenizing_error failed"); + return tl::unexpected(*error); + } + // Continue + continue; + } + + // Run add a token with default length given tokenizer, "name", name + // position, and name start. + tokenizer.add_token_with_default_length(token_type::NAME, name_position, + name_start); + continue; + } + + // If tokenizer’s code point is U+0028 ((): + if (tokenizer.code_point == '(') { + // Let depth be 1. + size_t depth = 1; + // Let regexp position be tokenizer’s next index. + auto regexp_position = tokenizer.next_index; + // Let regexp start be regexp position. + auto regexp_start = regexp_position; + // Let error be false. + bool error = false; + + // While regexp position is less than tokenizer’s input's code point + // length: + while (regexp_position < tokenizer.input.size()) { + // Run seek and get the next code point given tokenizer and regexp + // position. + tokenizer.seek_and_get_next_code_point(regexp_position); + + // TODO: Optimization opportunity: The next 2 if statements can be + // merged. If the result of running is ASCII given tokenizer’s code + // point is false: + if (!unicode::is_ascii(tokenizer.code_point)) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer’s index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + + // If regexp position equals regexp start and tokenizer’s code point is + // U+003F (?): + if (regexp_position == regexp_start && tokenizer.code_point == '?') { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer’s index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true; + error = true; + break; + } + + // If tokenizer’s code point is U+005C (\): + if (tokenizer.code_point == '\\') { + // If regexp position equals tokenizer’s input's code point length − 1 + if (regexp_position == tokenizer.input.size() - 1) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer’s index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + // Run get the next code point given tokenizer. + tokenizer.get_next_code_point(); + // If the result of running is ASCII given tokenizer’s code point is + // false: + if (!unicode::is_ascii(tokenizer.code_point)) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer’s index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index); + process_error.has_value()) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + // Set regexp position to tokenizer’s next index. + regexp_position = tokenizer.next_index; + continue; + } + + // If tokenizer’s code point is U+0029 ()): + if (tokenizer.code_point == ')') { + // Decrement depth by 1. + depth--; + // If depth is 0: + if (depth == 0) { + // Set regexp position to tokenizer’s next index. + regexp_position = tokenizer.next_index; + // Break. + break; + } + } else if (tokenizer.code_point == '(') { + // Otherwise if tokenizer’s code point is U+0028 ((): + // Increment depth by 1. + depth++; + // If regexp position equals tokenizer’s input's code point length − + // 1: + if (regexp_position == tokenizer.input.size() - 1) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer’s index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + // Let temporary position be tokenizer’s next index. + auto temporary_position = tokenizer.next_index; + // Run get the next code point given tokenizer. + tokenizer.get_next_code_point(); + // If tokenizer’s code point is not U+003F (?): + if (tokenizer.code_point != '?') { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer’s index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + // Set error to true. + error = true; + break; + } + // Set tokenizer’s next index to temporary position. + tokenizer.next_index = temporary_position; + } + // Set regexp position to tokenizer’s next index. + regexp_position = tokenizer.next_index; + } + + // If error is true continue. + if (error) continue; + // If depth is not zero: + if (depth != 0) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer’s index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + return tl::unexpected(*process_error); + } + continue; + } + // Let regexp length be regexp position − regexp start − 1. + auto regexp_length = regexp_position - regexp_start - 1; + // If regexp length is zero: + if (regexp_length == 0) { + // Run process a tokenizing error given tokenizer, regexp start, and + // tokenizer’s index. + if (auto process_error = tokenizer.process_tokenizing_error( + regexp_start, tokenizer.index)) { + ada_log("process_tokenizing_error failed"); + return tl::unexpected(*process_error); + } + continue; + } + // Run add a token given tokenizer, "regexp", regexp position, regexp + // start, and regexp length. + tokenizer.add_token(token_type::REGEXP, regexp_position, regexp_start, + regexp_length); + continue; + } + // Run add a token with default position and length given tokenizer and + // "char". + tokenizer.add_token_with_defaults(token_type::CHAR); + } + // Run add a token with default length given tokenizer, "end", tokenizer’s + // index, and tokenizer’s index. + tokenizer.add_token_with_default_length(token_type::END, tokenizer.index, + tokenizer.index); + + ada_log("tokenizer.token_list size is: ", tokenizer.token_list.size()); + // Return tokenizer’s token list. + return tokenizer.token_list; +} + +std::string escape_pattern_string(std::string_view input) { + ada_log("escape_pattern_string called with input=", input); + if (input.empty()) [[unlikely]] { + return ""; + } + // Assert: input is an ASCII string. + ADA_ASSERT_TRUE(ada::idna::is_ascii(input)); + // Let result be the empty string. + std::string result{}; + result.reserve(input.size()); + + // TODO: Optimization opportunity: Use a lookup table + constexpr auto should_escape = [](const char c) { + return c == '+' || c == '*' || c == '?' || c == ':' || c == '{' || + c == '}' || c == '(' || c == ')' || c == '\\'; + }; + + // While index is less than input’s length: + for (const auto& c : input) { + if (should_escape(c)) { + // then append U+005C (\) to the end of result. + result.append("\\"); + } + + // Append c to the end of result. + result += c; + } + // Return result. + return result; +} + +namespace { +constexpr std::array escape_regexp_table = []() consteval { + std::array out{}; + for (auto& c : {'.', '+', '*', '?', '^', '$', '{', '}', '(', ')', '[', ']', + '|', '/', '\\'}) { + out[c] = 1; + } + return out; +}(); + +constexpr bool should_escape_regexp_char(char c) { + return escape_regexp_table[(uint8_t)c]; +} +} // namespace + +std::string escape_regexp_string(std::string_view input) { + // Assert: input is an ASCII string. + ADA_ASSERT_TRUE(idna::is_ascii(input)); + // Let result be the empty string. + std::string result{}; + result.reserve(input.size()); + for (const auto& c : input) { + // TODO: Optimize this even further + if (should_escape_regexp_char(c)) { + result.append(std::string("\\") + c); + } else { + result.push_back(c); + } + } + return result; +} + +std::string process_base_url_string(std::string_view input, + std::string_view type) { + // If type is not "pattern" return input. + if (type != "pattern") { + return std::string(input); + } + // Return the result of escaping a pattern string given input. + return escape_pattern_string(input); +} + +constexpr bool is_absolute_pathname(std::string_view input, + std::string_view type) noexcept { + // If input is the empty string, then return false. + if (input.empty()) [[unlikely]] { + return false; + } + // If input[0] is U+002F (/), then return true. + if (input.starts_with("/")) return true; + // If type is "url", then return false. + if (type == "url") return false; + // If input’s code point length is less than 2, then return false. + if (input.size() < 2) return false; + // If input[0] is U+005C (\) and input[1] is U+002F (/), then return true. + if (input.starts_with("\\/")) return true; + // If input[0] is U+007B ({) and input[1] is U+002F (/), then return true. + if (input.starts_with("{/")) return true; + // Return false. + return false; +} + +std::string generate_pattern_string( + std::vector& part_list, + url_pattern_compile_component_options& options) { + // Let result be the empty string. + std::string result{}; + // Let index list be the result of getting the indices for part list. + // For each index of index list: + for (size_t index = 0; index < part_list.size(); index++) { + // Let part be part list[index]. + auto part = part_list[index]; + // Let previous part be part list[index - 1] if index is greater than 0, + // otherwise let it be null. + // TODO: Optimization opportunity. Find a way to avoid making a copy here. + std::optional previous_part = + index == 0 ? std::nullopt : std::optional(part_list[index - 1]); + // Let next part be part list[index + 1] if index is less than index list’s + // size - 1, otherwise let it be null. + std::optional next_part = + index < part_list.size() - 1 ? std::optional(part_list[index + 1]) + : std::nullopt; + // If part’s type is "fixed-text" then: + if (part.type == url_pattern_part_type::FIXED_TEXT) { + // If part’s modifier is "none" then: + if (part.modifier == url_pattern_part_modifier::none) { + // Append the result of running escape a pattern string given part’s + // value to the end of result. + result.append(escape_pattern_string(part.value)); + continue; + } + // Append "{" to the end of result. + result += "{"; + // Append the result of running escape a pattern string given part’s value + // to the end of result. + result.append(escape_pattern_string(part.value)); + // Append "}" to the end of result. + result += "}"; + // Append the result of running convert a modifier to a string given + // part’s modifier to the end of result. + result.append(convert_modifier_to_string(part.modifier)); + continue; + } + // Let custom name be true if part’s name[0] is not an ASCII digit; + // otherwise false. + bool custom_name = !unicode::is_ascii_digit(part.name[0]); + // Let needs grouping be true if at least one of the following are true, + // otherwise let it be false: + // - part’s suffix is not the empty string. + // - part’s prefix is not the empty string and is not options’s prefix code + // point. + bool needs_grouping = + !part.suffix.empty() || + (!part.prefix.empty() && part.prefix[0] != options.get_prefix()[0]); + + // If all of the following are true: + // - needs grouping is false; and + // - custom name is true; and + // - part’s type is "segment-wildcard"; and + // - part’s modifier is "none"; and + // - next part is not null; and + // - next part’s prefix is the empty string; and + // - next part’s suffix is the empty string + if (!needs_grouping && custom_name && + part.type == url_pattern_part_type::SEGMENT_WILDCARD && + part.modifier == url_pattern_part_modifier::none && + next_part.has_value() && next_part->prefix.empty() && + next_part->suffix.empty()) { + // If next part’s type is "fixed-text": + if (next_part->type == url_pattern_part_type::FIXED_TEXT) { + // Set needs grouping to true if the result of running is a valid name + // code point given next part’s value's first code point and the boolean + // false is true. + if (idna::valid_name_code_point(next_part->value[0], false)) { + needs_grouping = true; + } + } else { + // Set needs grouping to true if next part’s name[0] is an ASCII digit. + needs_grouping = !next_part->name.empty() && + unicode::is_ascii_digit(next_part->name[0]); + } + } + + // If all of the following are true: + // - needs grouping is false; and + // - part’s prefix is the empty string; and + // - previous part is not null; and + // - previous part’s type is "fixed-text"; and + // - previous part’s value's last code point is options’s prefix code point. + // then set needs grouping to true. + if (!needs_grouping && part.prefix.empty() && previous_part.has_value() && + previous_part->type == url_pattern_part_type::FIXED_TEXT && + !options.get_prefix().empty() && + previous_part->value.at(previous_part->value.size() - 1) == + options.get_prefix()[0]) { + needs_grouping = true; + } + + // Assert: part’s name is not the empty string or null. + ADA_ASSERT_TRUE(!part.name.empty()); + + // If needs grouping is true, then append "{" to the end of result. + if (needs_grouping) { + result.append("{"); + } + + // Append the result of running escape a pattern string given part’s prefix + // to the end of result. + result.append(escape_pattern_string(part.prefix)); + + // If custom name is true: + if (custom_name) { + // Append ":" to the end of result. + result.append(":"); + // Append part’s name to the end of result. + result.append(part.name); + } + + // If part’s type is "regexp" then: + if (part.type == url_pattern_part_type::REGEXP) { + // Append "(" to the end of result. + result.append("("); + // Append part’s value to the end of result. + result.append(part.value); + // Append ")" to the end of result. + result.append(")"); + } else if (part.type == url_pattern_part_type::SEGMENT_WILDCARD && + !custom_name) { + // Otherwise if part’s type is "segment-wildcard" and custom name is + // false: Append "(" to the end of result. + result.append("("); + // Append the result of running generate a segment wildcard regexp given + // options to the end of result. + result.append(generate_segment_wildcard_regexp(options)); + // Append ")" to the end of result. + result.append(")"); + } else if (part.type == url_pattern_part_type::FULL_WILDCARD) { + // Otherwise if part’s type is "full-wildcard": + // If custom name is false and one of the following is true: + // - previous part is null; or + // - previous part’s type is "fixed-text"; or + // - previous part’s modifier is not "none"; or + // - needs grouping is true; or + // - part’s prefix is not the empty string + // - then append "*" to the end of result. + if (!custom_name && + (!previous_part.has_value() || + previous_part->type == url_pattern_part_type::FIXED_TEXT || + previous_part->modifier != url_pattern_part_modifier::none || + needs_grouping || !part.prefix.empty())) { + result.append("*"); + } else { + // Append "(" to the end of result. + // Append full wildcard regexp value to the end of result. + // Append ")" to the end of result. + result.append("(.*)"); + } + } + + // If all of the following are true: + // - part’s type is "segment-wildcard"; and + // - custom name is true; and + // - part’s suffix is not the empty string; and + // - The result of running is a valid name code point given part’s suffix's + // first code point and the boolean false is true then append U+005C (\) to + // the end of result. + if (part.type == url_pattern_part_type::SEGMENT_WILDCARD && custom_name && + !part.suffix.empty() && + idna::valid_name_code_point(part.suffix[0], false)) { + result.append("\\"); + } + + // Append the result of running escape a pattern string given part’s suffix + // to the end of result. + result.append(escape_pattern_string(part.suffix)); + // If needs grouping is true, then append "}" to the end of result. + if (needs_grouping) result.append("}"); + // Append the result of running convert a modifier to a string given part’s + // modifier to the end of result. + result.append(convert_modifier_to_string(part.modifier)); + } + // Return result. + return result; +} +} // namespace ada::url_pattern_helpers +/* end file src/url_pattern_helpers.cpp */ +/* begin file src/url_pattern_regex.cpp */ + +namespace ada::url_pattern_regex { + +#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER +std::optional std_regex_provider::create_instance( + std::string_view pattern, bool ignore_case) { + // Let flags be an empty string. + // If options’s ignore case is true then set flags to "vi". + // Otherwise set flags to "v" + auto flags = ignore_case + ? std::regex::icase | std::regex_constants::ECMAScript + : std::regex_constants::ECMAScript; + try { + return std::regex(pattern.data(), pattern.size(), flags); + } catch (const std::regex_error& e) { + (void)e; + ada_log("std_regex_provider::create_instance failed:", e.what()); + return std::nullopt; + } +} + +std::optional>> +std_regex_provider::regex_search(std::string_view input, + const std::regex& pattern) { + std::string input_str( + input.begin(), + input.end()); // Convert string_view to string for regex_search + std::smatch match_result; + if (!std::regex_search(input_str, match_result, pattern, + std::regex_constants::match_any)) { + return std::nullopt; + } + std::vector> matches; + // If input is empty, let's assume the result will be empty as well. + if (input.empty() || match_result.empty()) { + return matches; + } + matches.reserve(match_result.size()); + for (size_t i = 1; i < match_result.size(); ++i) { + if (auto entry = match_result[i]; entry.matched) { + matches.emplace_back(entry.str()); + } + } + return matches; +} + +bool std_regex_provider::regex_match(std::string_view input, + const std::regex& pattern) { + return std::regex_match(input.begin(), input.end(), pattern); +} + +#endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER + +} // namespace ada::url_pattern_regex +/* end file src/url_pattern_regex.cpp */ +/* begin file src/ada_c.cpp */ + +ada::result& get_instance(void* result) noexcept { + return *(ada::result*)result; +} + +extern "C" { +typedef void* ada_url; +typedef void* ada_url_search_params; +typedef void* ada_strings; +typedef void* ada_url_search_params_keys_iter; +typedef void* ada_url_search_params_values_iter; +typedef void* ada_url_search_params_entries_iter; + +struct ada_string { + const char* data; + size_t length; +}; + +struct ada_owned_string { + const char* data; + size_t length; +}; + +struct ada_string_pair { + ada_string key; + ada_string value; +}; + +ada_string ada_string_create(const char* data, size_t length) { + ada_string out{}; + out.data = data; + out.length = length; + return out; +} + +struct ada_url_components { + /* + * By using 32-bit integers, we implicitly assume that the URL string + * cannot exceed 4 GB. + * + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + */ + uint32_t protocol_end; + /** + * Username end is not `omitted` by default (-1) to make username and password + * getters less costly to implement. + */ + uint32_t username_end; + uint32_t host_start; + uint32_t host_end; + uint32_t port; + uint32_t pathname_start; + uint32_t search_start; + uint32_t hash_start; +}; + +ada_url ada_parse(const char* input, size_t length) noexcept { + return new ada::result( + ada::parse(std::string_view(input, length))); +} + +ada_url ada_parse_with_base(const char* input, size_t input_length, + const char* base, size_t base_length) noexcept { + auto base_out = + ada::parse(std::string_view(base, base_length)); + + if (!base_out) { + return new ada::result(base_out); + } + + return new ada::result(ada::parse( + std::string_view(input, input_length), &base_out.value())); +} + +bool ada_can_parse(const char* input, size_t length) noexcept { + return ada::can_parse(std::string_view(input, length)); +} + +bool ada_can_parse_with_base(const char* input, size_t input_length, + const char* base, size_t base_length) noexcept { + std::string_view base_view(base, base_length); + return ada::can_parse(std::string_view(input, input_length), &base_view); +} + +void ada_free(ada_url result) noexcept { + auto* r = (ada::result*)result; + delete r; +} + +ada_url ada_copy(ada_url input) noexcept { + ada::result& r = get_instance(input); + return new ada::result(r); +} + +bool ada_is_valid(ada_url result) noexcept { + ada::result& r = get_instance(result); + return r.has_value(); +} + +// caller must free the result with ada_free_owned_string +ada_owned_string ada_get_origin(ada_url result) noexcept { + ada::result& r = get_instance(result); + ada_owned_string owned{}; + if (!r) { + owned.data = nullptr; + owned.length = 0; + return owned; + } + std::string out = r->get_origin(); + owned.length = out.size(); + owned.data = new char[owned.length]; + memcpy((void*)owned.data, out.data(), owned.length); + return owned; +} + +void ada_free_owned_string(ada_owned_string owned) noexcept { + delete[] owned.data; +} + +ada_string ada_get_href(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_href(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_username(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_username(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_password(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_password(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_port(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_port(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_hash(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_hash(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_host(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_host(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_hostname(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_hostname(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_pathname(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_pathname(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_search(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_search(); + return ada_string_create(out.data(), out.length()); +} + +ada_string ada_get_protocol(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view out = r->get_protocol(); + return ada_string_create(out.data(), out.length()); +} + +uint8_t ada_get_host_type(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return 0; + } + return r->host_type; +} + +uint8_t ada_get_scheme_type(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return 0; + } + return r->type; +} + +bool ada_set_href(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_href(std::string_view(input, length)); +} + +bool ada_set_host(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_host(std::string_view(input, length)); +} + +bool ada_set_hostname(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_hostname(std::string_view(input, length)); +} + +bool ada_set_protocol(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_protocol(std::string_view(input, length)); +} + +bool ada_set_username(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_username(std::string_view(input, length)); +} + +bool ada_set_password(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_password(std::string_view(input, length)); +} + +bool ada_set_port(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_port(std::string_view(input, length)); +} + +bool ada_set_pathname(ada_url result, const char* input, + size_t length) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->set_pathname(std::string_view(input, length)); +} + +/** + * Update the search/query of the URL. + * + * If a URL has `?` as the search value, passing empty string to this function + * does not remove the attribute. If you need to remove it, please use + * `ada_clear_search` method. + */ +void ada_set_search(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->set_search(std::string_view(input, length)); + } +} + +/** + * Update the hash/fragment of the URL. + * + * If a URL has `#` as the hash value, passing empty string to this function + * does not remove the attribute. If you need to remove it, please use + * `ada_clear_hash` method. + */ +void ada_set_hash(ada_url result, const char* input, size_t length) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->set_hash(std::string_view(input, length)); + } +} + +void ada_clear_port(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->clear_port(); + } +} + +/** + * Removes the hash of the URL. + * + * Despite `ada_set_hash` method, this function allows the complete + * removal of the hash attribute, even if it has a value of `#`. + */ +void ada_clear_hash(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->clear_hash(); + } +} + +/** + * Removes the search of the URL. + * + * Despite `ada_set_search` method, this function allows the complete + * removal of the search attribute, even if it has a value of `?`. + */ +void ada_clear_search(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (r) { + r->clear_search(); + } +} + +bool ada_has_credentials(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_credentials(); +} + +bool ada_has_empty_hostname(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_empty_hostname(); +} + +bool ada_has_hostname(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_hostname(); +} + +bool ada_has_non_empty_username(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_non_empty_username(); +} + +bool ada_has_non_empty_password(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_non_empty_password(); +} + +bool ada_has_port(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_port(); +} + +bool ada_has_password(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_password(); +} + +bool ada_has_hash(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_hash(); +} + +bool ada_has_search(ada_url result) noexcept { + ada::result& r = get_instance(result); + if (!r) { + return false; + } + return r->has_search(); +} + +// returns a pointer to the internal url_aggregator::url_components +const ada_url_components* ada_get_components(ada_url result) noexcept { + static_assert(sizeof(ada_url_components) == sizeof(ada::url_components)); + ada::result& r = get_instance(result); + if (!r) { + return nullptr; + } + return reinterpret_cast(&r->get_components()); +} + +ada_owned_string ada_idna_to_unicode(const char* input, size_t length) { + std::string out = ada::idna::to_unicode(std::string_view(input, length)); + ada_owned_string owned{}; + owned.length = out.length(); + owned.data = new char[owned.length]; + memcpy((void*)owned.data, out.data(), owned.length); + return owned; +} + +ada_owned_string ada_idna_to_ascii(const char* input, size_t length) { + std::string out = ada::idna::to_ascii(std::string_view(input, length)); + ada_owned_string owned{}; + owned.length = out.size(); + owned.data = new char[owned.length]; + memcpy((void*)owned.data, out.data(), owned.length); + return owned; +} + +ada_url_search_params ada_parse_search_params(const char* input, + size_t length) { + return new ada::result( + ada::url_search_params(std::string_view(input, length))); +} + +void ada_free_search_params(ada_url_search_params result) { + auto* r = (ada::result*)result; + delete r; +} + +ada_owned_string ada_search_params_to_string(ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) return ada_owned_string{nullptr, 0}; + std::string out = r->to_string(); + ada_owned_string owned{}; + owned.length = out.size(); + owned.data = new char[owned.length]; + memcpy((void*)owned.data, out.data(), owned.length); + return owned; +} + +size_t ada_search_params_size(ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return 0; + } + return r->size(); +} + +void ada_search_params_sort(ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->sort(); + } +} + +void ada_search_params_reset(ada_url_search_params result, const char* input, + size_t length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->reset(std::string_view(input, length)); + } +} + +void ada_search_params_append(ada_url_search_params result, const char* key, + size_t key_length, const char* value, + size_t value_length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->append(std::string_view(key, key_length), + std::string_view(value, value_length)); + } +} + +void ada_search_params_set(ada_url_search_params result, const char* key, + size_t key_length, const char* value, + size_t value_length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->set(std::string_view(key, key_length), + std::string_view(value, value_length)); + } +} + +void ada_search_params_remove(ada_url_search_params result, const char* key, + size_t key_length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->remove(std::string_view(key, key_length)); + } +} + +void ada_search_params_remove_value(ada_url_search_params result, + const char* key, size_t key_length, + const char* value, size_t value_length) { + ada::result& r = + *(ada::result*)result; + if (r) { + r->remove(std::string_view(key, key_length), + std::string_view(value, value_length)); + } +} + +bool ada_search_params_has(ada_url_search_params result, const char* key, + size_t key_length) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return false; + } + return r->has(std::string_view(key, key_length)); +} + +bool ada_search_params_has_value(ada_url_search_params result, const char* key, + size_t key_length, const char* value, + size_t value_length) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return false; + } + return r->has(std::string_view(key, key_length), + std::string_view(value, value_length)); +} + +ada_string ada_search_params_get(ada_url_search_params result, const char* key, + size_t key_length) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return ada_string_create(nullptr, 0); + } + auto found = r->get(std::string_view(key, key_length)); + if (!found.has_value()) { + return ada_string_create(nullptr, 0); + } + return ada_string_create(found->data(), found->length()); +} + +ada_strings ada_search_params_get_all(ada_url_search_params result, + const char* key, size_t key_length) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return new ada::result>( + std::vector()); + } + return new ada::result>( + r->get_all(std::string_view(key, key_length))); +} + +ada_url_search_params_keys_iter ada_search_params_get_keys( + ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return new ada::result( + ada::url_search_params_keys_iter()); + } + return new ada::result(r->get_keys()); +} + +ada_url_search_params_values_iter ada_search_params_get_values( + ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return new ada::result( + ada::url_search_params_values_iter()); + } + return new ada::result(r->get_values()); +} + +ada_url_search_params_entries_iter ada_search_params_get_entries( + ada_url_search_params result) { + ada::result& r = + *(ada::result*)result; + if (!r) { + return new ada::result( + ada::url_search_params_entries_iter()); + } + return new ada::result(r->get_entries()); +} + +void ada_free_strings(ada_strings result) { + auto* r = (ada::result>*)result; + delete r; +} + +size_t ada_strings_size(ada_strings result) { + auto* r = (ada::result>*)result; + if (!r) { + return 0; + } + return (*r)->size(); +} + +ada_string ada_strings_get(ada_strings result, size_t index) { + auto* r = (ada::result>*)result; + if (!r) { + return ada_string_create(nullptr, 0); + } + std::string_view view = (*r)->at(index); + return ada_string_create(view.data(), view.length()); +} + +void ada_free_search_params_keys_iter(ada_url_search_params_keys_iter result) { + auto* r = (ada::result*)result; + delete r; +} + +ada_string ada_search_params_keys_iter_next( + ada_url_search_params_keys_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return ada_string_create(nullptr, 0); + } + auto next = (*r)->next(); + if (!next.has_value()) { + return ada_string_create(nullptr, 0); + } + return ada_string_create(next->data(), next->length()); +} + +bool ada_search_params_keys_iter_has_next( + ada_url_search_params_keys_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return false; + } + return (*r)->has_next(); +} + +void ada_free_search_params_values_iter( + ada_url_search_params_values_iter result) { + auto* r = (ada::result*)result; + delete r; +} + +ada_string ada_search_params_values_iter_next( + ada_url_search_params_values_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return ada_string_create(nullptr, 0); + } + auto next = (*r)->next(); + if (!next.has_value()) { + return ada_string_create(nullptr, 0); + } + return ada_string_create(next->data(), next->length()); +} + +bool ada_search_params_values_iter_has_next( + ada_url_search_params_values_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return false; + } + return (*r)->has_next(); +} + +void ada_free_search_params_entries_iter( + ada_url_search_params_entries_iter result) { + auto* r = (ada::result*)result; + delete r; +} + +ada_string_pair ada_search_params_entries_iter_next( + ada_url_search_params_entries_iter result) { + auto* r = (ada::result*)result; + if (!r) return {ada_string_create(nullptr, 0), ada_string_create(nullptr, 0)}; + auto next = (*r)->next(); + if (!next.has_value()) { + return {ada_string_create(nullptr, 0), ada_string_create(nullptr, 0)}; + } + return ada_string_pair{ + ada_string_create(next->first.data(), next->first.length()), + ada_string_create(next->second.data(), next->second.length())}; +} + +bool ada_search_params_entries_iter_has_next( + ada_url_search_params_entries_iter result) { + auto* r = (ada::result*)result; + if (!r) { + return false; + } + return (*r)->has_next(); +} + +} // extern "C" +/* end file src/ada_c.cpp */ +/* end file src/ada.cpp */ diff --git a/common/ada/ada.h b/common/ada/ada.h new file mode 100644 index 0000000000..b191694dcd --- /dev/null +++ b/common/ada/ada.h @@ -0,0 +1,10274 @@ +/* auto-generated on 2025-01-30 14:25:38 -0500. Do not edit! */ +/* begin file include/ada.h */ +/** + * @file ada.h + * @brief Includes all definitions for Ada. + */ +#ifndef ADA_H +#define ADA_H + +/* begin file include/ada/ada_idna.h */ +/* auto-generated on 2024-12-18 09:44:34 -0500. Do not edit! */ +/* begin file include/idna.h */ +#ifndef ADA_IDNA_H +#define ADA_IDNA_H + +/* begin file include/ada/idna/unicode_transcoding.h */ +#ifndef ADA_IDNA_UNICODE_TRANSCODING_H +#define ADA_IDNA_UNICODE_TRANSCODING_H + +#include +#include + +namespace ada::idna { + +size_t utf8_to_utf32(const char *buf, size_t len, char32_t *utf32_output); + +size_t utf8_length_from_utf32(const char32_t *buf, size_t len); + +size_t utf32_length_from_utf8(const char *buf, size_t len); + +size_t utf32_to_utf8(const char32_t *buf, size_t len, char *utf8_output); + +} // namespace ada::idna + +#endif // ADA_IDNA_UNICODE_TRANSCODING_H +/* end file include/ada/idna/unicode_transcoding.h */ +/* begin file include/ada/idna/mapping.h */ +#ifndef ADA_IDNA_MAPPING_H +#define ADA_IDNA_MAPPING_H + +#include +#include + +namespace ada::idna { + +// If the input is ascii, then the mapping is just -> lower case. +void ascii_map(char *input, size_t length); +// check whether an ascii string needs mapping +bool ascii_has_upper_case(char *input, size_t length); +// Map the characters according to IDNA, returning the empty string on error. +std::u32string map(std::u32string_view input); + +} // namespace ada::idna + +#endif +/* end file include/ada/idna/mapping.h */ +/* begin file include/ada/idna/normalization.h */ +#ifndef ADA_IDNA_NORMALIZATION_H +#define ADA_IDNA_NORMALIZATION_H + +#include +#include + +namespace ada::idna { + +// Normalize the characters according to IDNA (Unicode Normalization Form C). +void normalize(std::u32string &input); + +} // namespace ada::idna +#endif +/* end file include/ada/idna/normalization.h */ +/* begin file include/ada/idna/punycode.h */ +#ifndef ADA_IDNA_PUNYCODE_H +#define ADA_IDNA_PUNYCODE_H + +#include +#include + +namespace ada::idna { + +bool punycode_to_utf32(std::string_view input, std::u32string &out); +bool verify_punycode(std::string_view input); +bool utf32_to_punycode(std::u32string_view input, std::string &out); + +} // namespace ada::idna + +#endif // ADA_IDNA_PUNYCODE_H +/* end file include/ada/idna/punycode.h */ +/* begin file include/ada/idna/validity.h */ +#ifndef ADA_IDNA_VALIDITY_H +#define ADA_IDNA_VALIDITY_H + +#include +#include + +namespace ada::idna { + +/** + * @see https://www.unicode.org/reports/tr46/#Validity_Criteria + */ +bool is_label_valid(std::u32string_view label); + +} // namespace ada::idna + +#endif // ADA_IDNA_VALIDITY_H +/* end file include/ada/idna/validity.h */ +/* begin file include/ada/idna/to_ascii.h */ +#ifndef ADA_IDNA_TO_ASCII_H +#define ADA_IDNA_TO_ASCII_H + +#include +#include + +namespace ada::idna { + +// Converts a domain (e.g., www.google.com) possibly containing international +// characters to an ascii domain (with punycode). It will not do percent +// decoding: percent decoding should be done prior to calling this function. We +// do not remove tabs and spaces, they should have been removed prior to calling +// this function. We also do not trim control characters. We also assume that +// the input is not empty. We return "" on error. +// +// +// This function may accept or even produce invalid domains. +std::string to_ascii(std::string_view ut8_string); + +// Returns true if the string contains a forbidden code point according to the +// WHATGL URL specification: +// https://url.spec.whatwg.org/#forbidden-domain-code-point +bool contains_forbidden_domain_code_point(std::string_view ascii_string); + +bool constexpr is_ascii(std::u32string_view view); +bool constexpr is_ascii(std::string_view view); + +} // namespace ada::idna + +#endif // ADA_IDNA_TO_ASCII_H +/* end file include/ada/idna/to_ascii.h */ +/* begin file include/ada/idna/to_unicode.h */ + +#ifndef ADA_IDNA_TO_UNICODE_H +#define ADA_IDNA_TO_UNICODE_H + +#include + +namespace ada::idna { + +std::string to_unicode(std::string_view input); + +} // namespace ada::idna + +#endif // ADA_IDNA_TO_UNICODE_H +/* end file include/ada/idna/to_unicode.h */ +/* begin file include/ada/idna/identifier.h */ +#ifndef ADA_IDNA_IDENTIFIER_H +#define ADA_IDNA_IDENTIFIER_H + +#include +#include + +namespace ada::idna { + +// Access the first code point of the input string. +// Verify if it is valid name code point given a Unicode code point and a +// boolean first: If first is true return the result of checking if code point +// is contained in the IdentifierStart set of code points. Otherwise return the +// result of checking if code point is contained in the IdentifierPart set of +// code points. Returns false if the input is empty or the code point is not +// valid. There is minimal Unicode error handling: the input should be valid +// UTF-8. https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point +bool valid_name_code_point(char32_t input, bool first); + +} // namespace ada::idna + +#endif +/* end file include/ada/idna/identifier.h */ + +#endif +/* end file include/idna.h */ +/* end file include/ada/ada_idna.h */ +/* begin file include/ada/character_sets.h */ +/** + * @file character_sets.h + * @brief Declaration of the character sets used by unicode functions. + * @author Node.js + * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc + */ +#ifndef ADA_CHARACTER_SETS_H +#define ADA_CHARACTER_SETS_H + +/* begin file include/ada/common_defs.h */ +/** + * @file common_defs.h + * @brief Common definitions for cross-platform compiler support. + */ +#ifndef ADA_COMMON_DEFS_H +#define ADA_COMMON_DEFS_H + +// https://en.cppreference.com/w/cpp/feature_test#Library_features +// detect C++20 features +#include + +#ifdef _MSC_VER +#define ADA_VISUAL_STUDIO 1 +/** + * We want to differentiate carefully between + * clang under visual studio and regular visual + * studio. + */ +#ifdef __clang__ +// clang under visual studio +#define ADA_CLANG_VISUAL_STUDIO 1 +#else +// just regular visual studio (best guess) +#define ADA_REGULAR_VISUAL_STUDIO 1 +#endif // __clang__ +#endif // _MSC_VER + +#if defined(__GNUC__) +// Marks a block with a name so that MCA analysis can see it. +#define ADA_BEGIN_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-BEGIN " #name); +#define ADA_END_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-END " #name); +#define ADA_DEBUG_BLOCK(name, block) \ + BEGIN_DEBUG_BLOCK(name); \ + block; \ + END_DEBUG_BLOCK(name); +#else +#define ADA_BEGIN_DEBUG_BLOCK(name) +#define ADA_END_DEBUG_BLOCK(name) +#define ADA_DEBUG_BLOCK(name, block) +#endif + +// Align to N-byte boundary +#define ADA_ROUNDUP_N(a, n) (((a) + ((n) - 1)) & ~((n) - 1)) +#define ADA_ROUNDDOWN_N(a, n) ((a) & ~((n) - 1)) + +#define ADA_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n) - 1)) == 0) + +#if defined(ADA_REGULAR_VISUAL_STUDIO) + +#define ada_really_inline __forceinline +#define ada_never_inline __declspec(noinline) + +#define ada_unused +#define ada_warn_unused + +#define ADA_PUSH_DISABLE_WARNINGS __pragma(warning(push)) +#define ADA_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0)) +#define ADA_DISABLE_VS_WARNING(WARNING_NUMBER) \ + __pragma(warning(disable : WARNING_NUMBER)) +// Get rid of Intellisense-only warnings (Code Analysis) +// Though __has_include is C++17, it is supported in Visual Studio 2017 or +// better (_MSC_VER>=1910). +#ifdef __has_include +#if __has_include() +#include +#define ADA_DISABLE_UNDESIRED_WARNINGS \ + ADA_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS) +#endif +#endif + +#ifndef ADA_DISABLE_UNDESIRED_WARNINGS +#define ADA_DISABLE_UNDESIRED_WARNINGS +#endif + +#define ADA_DISABLE_DEPRECATED_WARNING ADA_DISABLE_VS_WARNING(4996) +#define ADA_DISABLE_STRICT_OVERFLOW_WARNING +#define ADA_POP_DISABLE_WARNINGS __pragma(warning(pop)) + +#else // ADA_REGULAR_VISUAL_STUDIO + +#define ada_really_inline inline __attribute__((always_inline)) +#define ada_never_inline inline __attribute__((noinline)) + +#define ada_unused __attribute__((unused)) +#define ada_warn_unused __attribute__((warn_unused_result)) + +#define ADA_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push") +// gcc doesn't seem to disable all warnings with all and extra, add warnings +// here as necessary +#define ADA_PUSH_DISABLE_ALL_WARNINGS \ + ADA_PUSH_DISABLE_WARNINGS \ + ADA_DISABLE_GCC_WARNING("-Weffc++") \ + ADA_DISABLE_GCC_WARNING("-Wall") \ + ADA_DISABLE_GCC_WARNING("-Wconversion") \ + ADA_DISABLE_GCC_WARNING("-Wextra") \ + ADA_DISABLE_GCC_WARNING("-Wattributes") \ + ADA_DISABLE_GCC_WARNING("-Wimplicit-fallthrough") \ + ADA_DISABLE_GCC_WARNING("-Wnon-virtual-dtor") \ + ADA_DISABLE_GCC_WARNING("-Wreturn-type") \ + ADA_DISABLE_GCC_WARNING("-Wshadow") \ + ADA_DISABLE_GCC_WARNING("-Wunused-parameter") \ + ADA_DISABLE_GCC_WARNING("-Wunused-variable") +#define ADA_PRAGMA(P) _Pragma(#P) +#define ADA_DISABLE_GCC_WARNING(WARNING) \ + ADA_PRAGMA(GCC diagnostic ignored WARNING) +#if defined(ADA_CLANG_VISUAL_STUDIO) +#define ADA_DISABLE_UNDESIRED_WARNINGS \ + ADA_DISABLE_GCC_WARNING("-Wmicrosoft-include") +#else +#define ADA_DISABLE_UNDESIRED_WARNINGS +#endif +#define ADA_DISABLE_DEPRECATED_WARNING \ + ADA_DISABLE_GCC_WARNING("-Wdeprecated-declarations") +#define ADA_DISABLE_STRICT_OVERFLOW_WARNING \ + ADA_DISABLE_GCC_WARNING("-Wstrict-overflow") +#define ADA_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop") + +#endif // MSC_VER + +#if defined(ADA_VISUAL_STUDIO) +/** + * It does not matter here whether you are using + * the regular visual studio or clang under visual + * studio. + */ +#if ADA_USING_LIBRARY +#define ADA_DLLIMPORTEXPORT __declspec(dllimport) +#else +#define ADA_DLLIMPORTEXPORT __declspec(dllexport) +#endif +#else +#define ADA_DLLIMPORTEXPORT +#endif + +/// If EXPR is an error, returns it. +#define ADA_TRY(EXPR) \ + { \ + auto _err = (EXPR); \ + if (_err) { \ + return _err; \ + } \ + } + +// __has_cpp_attribute is part of C++20 +#if !defined(__has_cpp_attribute) +#define __has_cpp_attribute(x) 0 +#endif + +#if __has_cpp_attribute(gnu::noinline) +#define ADA_ATTRIBUTE_NOINLINE [[gnu::noinline]] +#else +#define ADA_ATTRIBUTE_NOINLINE +#endif + +namespace ada { +[[noreturn]] inline void unreachable() { +#ifdef __GNUC__ + __builtin_unreachable(); +#elif defined(_MSC_VER) + __assume(false); +#else +#endif +} +} // namespace ada + +// Unless the programmer has already set ADA_DEVELOPMENT_CHECKS, +// we want to set it under debug builds. We detect a debug build +// under Visual Studio when the _DEBUG macro is set. Under the other +// compilers, we use the fact that they define __OPTIMIZE__ whenever +// they allow optimizations. +// It is possible that this could miss some cases where ADA_DEVELOPMENT_CHECKS +// is helpful, but the programmer can set the macro ADA_DEVELOPMENT_CHECKS. +// It could also wrongly set ADA_DEVELOPMENT_CHECKS (e.g., if the programmer +// sets _DEBUG in a release build under Visual Studio, or if some compiler fails +// to set the __OPTIMIZE__ macro). +#if !defined(ADA_DEVELOPMENT_CHECKS) && !defined(NDEBUG) +#ifdef _MSC_VER +// Visual Studio seems to set _DEBUG for debug builds. +#ifdef _DEBUG +#define ADA_DEVELOPMENT_CHECKS 1 +#endif // _DEBUG +#else // _MSC_VER +// All other compilers appear to set __OPTIMIZE__ to a positive integer +// when the compiler is optimizing. +#ifndef __OPTIMIZE__ +#define ADA_DEVELOPMENT_CHECKS 1 +#endif // __OPTIMIZE__ +#endif // _MSC_VER +#endif // ADA_DEVELOPMENT_CHECKS + +#define ADA_STR(x) #x + +#if ADA_DEVELOPMENT_CHECKS +#define ADA_REQUIRE(EXPR) \ + { \ + if (!(EXPR) { abort(); }) \ + } + +#define ADA_FAIL(MESSAGE) \ + do { \ + std::cerr << "FAIL: " << (MESSAGE) << std::endl; \ + abort(); \ + } while (0); +#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE) \ + do { \ + if (LHS != RHS) { \ + std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \ + ADA_FAIL(MESSAGE); \ + } \ + } while (0); +#define ADA_ASSERT_TRUE(COND) \ + do { \ + if (!(COND)) { \ + std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \ + << std::endl; \ + ADA_FAIL(ADA_STR(COND)); \ + } \ + } while (0); +#else +#define ADA_FAIL(MESSAGE) +#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE) +#define ADA_ASSERT_TRUE(COND) +#endif + +#ifdef ADA_VISUAL_STUDIO +#define ADA_ASSUME(COND) __assume(COND) +#else +#define ADA_ASSUME(COND) \ + do { \ + if (!(COND)) { \ + __builtin_unreachable(); \ + } \ + } while (0) +#endif + +#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \ + (defined(_M_AMD64) || defined(_M_X64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP == 2)) +#define ADA_SSE2 1 +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) +#define ADA_NEON 1 +#endif + +#ifndef __has_cpp_attribute +#define ada_lifetime_bound +#elif __has_cpp_attribute(msvc::lifetimebound) +#define ada_lifetime_bound [[msvc::lifetimebound]] +#elif __has_cpp_attribute(clang::lifetimebound) +#define ada_lifetime_bound [[clang::lifetimebound]] +#elif __has_cpp_attribute(lifetimebound) +#define ada_lifetime_bound [[lifetimebound]] +#else +#define ada_lifetime_bound +#endif + +#ifdef __cpp_lib_format +#if __cpp_lib_format >= 202110L +#include +#define ADA_HAS_FORMAT 1 +#endif +#endif + +#endif // ADA_COMMON_DEFS_H +/* end file include/ada/common_defs.h */ +#include + +/** + * These functions are not part of our public API and may + * change at any time. + * @private + * @namespace ada::character_sets + * @brief Includes the definitions for unicode character sets. + */ +namespace ada::character_sets { +ada_really_inline constexpr bool bit_at(const uint8_t a[], uint8_t i); +} // namespace ada::character_sets + +#endif // ADA_CHARACTER_SETS_H +/* end file include/ada/character_sets.h */ +/* begin file include/ada/character_sets-inl.h */ +/** + * @file character_sets-inl.h + * @brief Definitions of the character sets used by unicode functions. + * @author Node.js + * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc + */ +#ifndef ADA_CHARACTER_SETS_INL_H +#define ADA_CHARACTER_SETS_INL_H + +/** + * These functions are not part of our public API and may + * change at any time. + * @private + */ +namespace ada::character_sets { + +constexpr char hex[1024] = "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0" + "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0" + "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0" + "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0" + "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0" + "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0" + "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0" + "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0" + "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0" + "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0" + "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0" + "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0" + "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0" + "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0" + "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0" + "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0" + "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0" + "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0" + "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0" + "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0" + "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0" + "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0" + "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0" + "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0" + "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0" + "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0" + "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0" + "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0" + "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0" + "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0" + "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0" + "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF"; + +constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t QUERY_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 40 41 42 43 44 45 46 47 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t PATH_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00, + // 28 29 2A 2B 2C 2D 2E 2F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80, + // 40 41 42 43 44 45 46 47 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = { + // 00 01 02 03 04 05 06 07 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 08 09 0A 0B 0C 0D 0E 0F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 10 11 12 13 14 15 16 17 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 18 19 1A 1B 1C 1D 1E 1F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 20 21 22 23 24 25 26 27 + 0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 28 29 2A 2B 2C 2D 2E 2F + 0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x80, + // 30 31 32 33 34 35 36 37 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 38 39 3A 3B 3C 3D 3E 3F + 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 40 41 42 43 44 45 46 47 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 48 49 4A 4B 4C 4D 4E 4F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 50 51 52 53 54 55 56 57 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 58 59 5A 5B 5C 5D 5E 5F + 0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x40 | 0x00, + // 60 61 62 63 64 65 66 67 + 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 68 69 6A 6B 6C 6D 6E 6F + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 70 71 72 73 74 75 76 77 + 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00, + // 78 79 7A 7B 7C 7D 7E 7F + 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 80 81 82 83 84 85 86 87 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 88 89 8A 8B 8C 8D 8E 8F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 90 91 92 93 94 95 96 97 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // 98 99 9A 9B 9C 9D 9E 9F + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A0 A1 A2 A3 A4 A5 A6 A7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // A8 A9 AA AB AC AD AE AF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B0 B1 B2 B3 B4 B5 B6 B7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // B8 B9 BA BB BC BD BE BF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C0 C1 C2 C3 C4 C5 C6 C7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // C8 C9 CA CB CC CD CE CF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D0 D1 D2 D3 D4 D5 D6 D7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // D8 D9 DA DB DC DD DE DF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E0 E1 E2 E3 E4 E5 E6 E7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // E8 E9 EA EB EC ED EE EF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F0 F1 F2 F3 F4 F5 F6 F7 + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80, + // F8 F9 FA FB FC FD FE FF + 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80}; + +ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) { + return !!(a[i >> 3] & (1 << (i & 7))); +} + +} // namespace ada::character_sets + +#endif // ADA_CHARACTER_SETS_INL_H +/* end file include/ada/character_sets-inl.h */ +/* begin file include/ada/checkers-inl.h */ +/** + * @file checkers-inl.h + * @brief Definitions for URL specific checkers used within Ada. + */ +#ifndef ADA_CHECKERS_INL_H +#define ADA_CHECKERS_INL_H + +#include +#include + +namespace ada::checkers { + +constexpr bool has_hex_prefix_unsafe(std::string_view input) { + // This is actually efficient code, see has_hex_prefix for the assembly. + constexpr bool is_little_endian = std::endian::native == std::endian::little; + constexpr uint16_t word0x = 0x7830; + uint16_t two_first_bytes = + static_cast(input[0]) | + static_cast((static_cast(input[1]) << 8)); + if constexpr (is_little_endian) { + two_first_bytes |= 0x2000; + } else { + two_first_bytes |= 0x020; + } + return two_first_bytes == word0x; +} + +constexpr bool has_hex_prefix(std::string_view input) { + return input.size() >= 2 && has_hex_prefix_unsafe(input); +} + +constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); } + +constexpr char to_lower(char x) noexcept { return (x | 0x20); } + +constexpr bool is_alpha(char x) noexcept { + return (to_lower(x) >= 'a') && (to_lower(x) <= 'z'); +} + +constexpr bool is_windows_drive_letter(std::string_view input) noexcept { + return input.size() >= 2 && + (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) && + ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' || + input[2] == '?' || input[2] == '#')); +} + +constexpr bool +is_normalized_windows_drive_letter(std::string_view input) noexcept { + return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':')); +} + +} // namespace ada::checkers + +#endif // ADA_CHECKERS_INL_H +/* end file include/ada/checkers-inl.h */ +/* begin file include/ada/log.h */ +/** + * @file log.h + * @brief Includes the definitions for logging. + * @private Excluded from docs through the doxygen file. + */ +#ifndef ADA_LOG_H +#define ADA_LOG_H + +// To enable logging, set ADA_LOGGING to 1: +#ifndef ADA_LOGGING +#define ADA_LOGGING 0 +#endif + +#if ADA_LOGGING +#include +#endif // ADA_LOGGING + +namespace ada { + +/** + * Log a message. If you want to have no overhead when logging is disabled, use + * the ada_log macro. + * @private + */ +template +constexpr ada_really_inline void log([[maybe_unused]] Args... args) { +#if ADA_LOGGING + ((std::cout << "ADA_LOG: ") << ... << args) << std::endl; +#endif // ADA_LOGGING +} +} // namespace ada + +#if ADA_LOGGING +#ifndef ada_log +#define ada_log(...) \ + do { \ + ada::log(__VA_ARGS__); \ + } while (0) +#endif // ada_log +#else +#define ada_log(...) +#endif // ADA_LOGGING + +#endif // ADA_LOG_H +/* end file include/ada/log.h */ +/* begin file include/ada/encoding_type.h */ +/** + * @file encoding_type.h + * @brief Definition for supported encoding types. + */ +#ifndef ADA_ENCODING_TYPE_H +#define ADA_ENCODING_TYPE_H + +#include + +namespace ada { + +/** + * This specification defines three encodings with the same names as encoding + * schemes defined in the Unicode standard: UTF-8, UTF-16LE, and UTF-16BE. + * + * @see https://encoding.spec.whatwg.org/#encodings + */ +enum class encoding_type { + UTF8, + UTF_16LE, + UTF_16BE, +}; + +/** + * Convert a encoding_type to string. + */ +ada_warn_unused std::string to_string(encoding_type type); + +} // namespace ada + +#endif // ADA_ENCODING_TYPE_H +/* end file include/ada/encoding_type.h */ +/* begin file include/ada/helpers.h */ +/** + * @file helpers.h + * @brief Definitions for helper functions used within Ada. + */ +#ifndef ADA_HELPERS_H +#define ADA_HELPERS_H + +/* begin file include/ada/url_base.h */ +/** + * @file url_base.h + * @brief Declaration for the basic URL definitions + */ +#ifndef ADA_URL_BASE_H +#define ADA_URL_BASE_H + +/* begin file include/ada/scheme.h */ +/** + * @file scheme.h + * @brief Declarations for the URL scheme. + */ +#ifndef ADA_SCHEME_H +#define ADA_SCHEME_H + +#include + +/** + * @namespace ada::scheme + * @brief Includes the scheme declarations + */ +namespace ada::scheme { + +/** + * Type of the scheme as an enum. + * Using strings to represent a scheme type is not ideal because + * checking for types involves string comparisons. It is faster to use + * a simple integer. + * In C++11, we are allowed to specify the underlying type of the enum. + * We pick an 8-bit integer (which allows up to 256 types). Specifying the + * type of the enum may help integration with other systems if the type + * variable is exposed (since its value will not depend on the compiler). + */ +enum type : uint8_t { + HTTP = 0, + NOT_SPECIAL = 1, + HTTPS = 2, + WS = 3, + FTP = 4, + WSS = 5, + FILE = 6 +}; + +/** + * A special scheme is an ASCII string that is listed in the first column of the + * following table. The default port for a special scheme is listed in the + * second column on the same row. The default port for any other ASCII string is + * null. + * + * @see https://url.spec.whatwg.org/#url-miscellaneous + * @param scheme + * @return If scheme is a special scheme + */ +ada_really_inline constexpr bool is_special(std::string_view scheme); + +/** + * A special scheme is an ASCII string that is listed in the first column of the + * following table. The default port for a special scheme is listed in the + * second column on the same row. The default port for any other ASCII string is + * null. + * + * @see https://url.spec.whatwg.org/#url-miscellaneous + * @param scheme + * @return The special port + */ +constexpr uint16_t get_special_port(std::string_view scheme) noexcept; + +/** + * Returns the port number of a special scheme. + * @see https://url.spec.whatwg.org/#special-scheme + */ +constexpr uint16_t get_special_port(ada::scheme::type type) noexcept; +/** + * Returns the scheme of an input, or NOT_SPECIAL if it's not a special scheme + * defined by the spec. + */ +constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept; + +} // namespace ada::scheme + +#endif // ADA_SCHEME_H +/* end file include/ada/scheme.h */ + +#include + +namespace ada { + +/** + * Type of URL host as an enum. + */ +enum url_host_type : uint8_t { + /** + * Represents common URLs such as "https://www.google.com" + */ + DEFAULT = 0, + /** + * Represents ipv4 addresses such as "http://127.0.0.1" + */ + IPV4 = 1, + /** + * Represents ipv6 addresses such as + * "http://[2001:db8:3333:4444:5555:6666:7777:8888]" + */ + IPV6 = 2, +}; + +/** + * @brief Base class of URL implementations + * + * @details A url_base contains a few attributes: is_valid, has_opaque_path and + * type. All non-trivial implementation details are in derived classes such as + * ada::url and ada::url_aggregator. + * + * It is an abstract class that cannot be instantiated directly. + */ +struct url_base { + virtual ~url_base() = default; + + /** + * Used for returning the validity from the result of the URL parser. + */ + bool is_valid{true}; + + /** + * A URL has an opaque path if its path is a string. + */ + bool has_opaque_path{false}; + + /** + * URL hosts type + */ + url_host_type host_type = url_host_type::DEFAULT; + + /** + * @private + */ + ada::scheme::type type{ada::scheme::type::NOT_SPECIAL}; + + /** + * A URL is special if its scheme is a special scheme. A URL is not special if + * its scheme is not a special scheme. + */ + [[nodiscard]] ada_really_inline constexpr bool is_special() const noexcept; + + /** + * The origin getter steps are to return the serialization of this's URL's + * origin. [HTML] + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#concept-url-origin + */ + [[nodiscard]] virtual std::string get_origin() const noexcept = 0; + + /** + * Returns true if this URL has a valid domain as per RFC 1034 and + * corresponding specifications. Among other things, it requires + * that the domain string has fewer than 255 octets. + */ + [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0; + + /** + * @private + * + * Return the 'special port' if the URL is special and not 'file'. + * Returns 0 otherwise. + */ + [[nodiscard]] inline uint16_t get_special_port() const noexcept; + + /** + * @private + * + * Get the default port if the url's scheme has one, returns 0 otherwise. + */ + [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept; + + /** + * @private + * + * Parse a port (16-bit decimal digit) from the provided input. + * We assume that the input does not contain spaces or tabs + * within the ASCII digits. + * It returns how many bytes were consumed when a number is successfully + * parsed. + * @return On failure, it returns zero. + * @see https://url.spec.whatwg.org/#host-parsing + */ + virtual size_t parse_port(std::string_view view, + bool check_trailing_content) noexcept = 0; + + virtual ada_really_inline size_t parse_port(std::string_view view) noexcept { + return this->parse_port(view, false); + } + + /** + * Returns a JSON string representation of this URL. + */ + [[nodiscard]] virtual std::string to_string() const = 0; + + /** @private */ + virtual inline void clear_pathname() = 0; + + /** @private */ + virtual inline void clear_search() = 0; + + /** @private */ + [[nodiscard]] virtual inline bool has_hash() const noexcept = 0; + + /** @private */ + [[nodiscard]] virtual inline bool has_search() const noexcept = 0; + +}; // url_base + +} // namespace ada + +#endif +/* end file include/ada/url_base.h */ + +#include +#include + +#if ADA_DEVELOPMENT_CHECKS +#include +#endif // ADA_DEVELOPMENT_CHECKS + +/** + * These functions are not part of our public API and may + * change at any time. + * + * @private + * @namespace ada::helpers + * @brief Includes the definitions for helper functions + */ +namespace ada::helpers { + +/** + * @private + */ +template +void encode_json(std::string_view view, out_iter out); + +/** + * @private + * This function is used to prune a fragment from a url, and returning the + * removed string if input has fragment. + * + * @details prune_hash seeks the first '#' and returns everything after it + * as a string_view, and modifies (in place) the input so that it points at + * everything before the '#'. If no '#' is found, the input is left unchanged + * and std::nullopt is returned. + * + * @attention The function is non-allocating and it does not throw. + * @returns Note that the returned string_view might be empty! + */ +ada_really_inline std::optional +prune_hash(std::string_view &input) noexcept; + +/** + * @private + * Defined by the URL specification, shorten a URLs paths. + * @see https://url.spec.whatwg.org/#shorten-a-urls-path + * @returns Returns true if path is shortened. + */ +ada_really_inline bool shorten_path(std::string &path, + ada::scheme::type type) noexcept; + +/** + * @private + * Defined by the URL specification, shorten a URLs paths. + * @see https://url.spec.whatwg.org/#shorten-a-urls-path + * @returns Returns true if path is shortened. + */ +ada_really_inline bool shorten_path(std::string_view &path, + ada::scheme::type type) noexcept; + +/** + * @private + * + * Parse the path from the provided input and append to the existing + * (possibly empty) path. The input cannot contain tabs and spaces: it + * is the user's responsibility to check. + * + * The input is expected to be UTF-8. + * + * @see https://url.spec.whatwg.org/ + */ +ada_really_inline void parse_prepared_path(std::string_view input, + ada::scheme::type type, + std::string &path); + +/** + * @private + * Remove and mutate all ASCII tab or newline characters from an input. + */ +ada_really_inline void remove_ascii_tab_or_newline(std::string &input) noexcept; + +/** + * @private + * Return the substring from input going from index pos to the end. + * This function cannot throw. + */ +ada_really_inline constexpr std::string_view substring(std::string_view input, + size_t pos) noexcept; + +/** + * @private + * Returns true if the string_view points within the string. + */ +bool overlaps(std::string_view input1, const std::string &input2) noexcept; + +/** + * @private + * Return the substring from input going from index pos1 to the pos2 (non + * included). The length of the substring is pos2 - pos1. + */ +ada_really_inline constexpr std::string_view +substring(std::string_view input, size_t pos1, size_t pos2) noexcept { +#if ADA_DEVELOPMENT_CHECKS + if (pos2 < pos1) { + std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")" + << std::endl; + abort(); + } +#endif + return input.substr(pos1, pos2 - pos1); +} + +/** + * @private + * Modify the string_view so that it has the new size pos, assuming that pos <= + * input.size(). This function cannot throw. + */ +ada_really_inline void resize(std::string_view &input, size_t pos) noexcept; + +/** + * @private + * Returns a host's delimiter location depending on the state of the instance, + * and whether a colon was found outside brackets. Used by the host parser. + */ +ada_really_inline std::pair +get_host_delimiter_location(bool is_special, std::string_view &view) noexcept; + +/** + * @private + * Removes leading and trailing C0 control and whitespace characters from + * string. + */ +void trim_c0_whitespace(std::string_view &input) noexcept; + +/** + * @private + * @see + * https://url.spec.whatwg.org/#potentially-strip-trailing-spaces-from-an-opaque-path + */ +template +ada_really_inline void +strip_trailing_spaces_from_opaque_path(url_type &url) noexcept; + +/** + * @private + * Finds the delimiter of a view in authority state. + */ +ada_really_inline size_t +find_authority_delimiter_special(std::string_view view) noexcept; + +/** + * @private + * Finds the delimiter of a view in authority state. + */ +ada_really_inline size_t +find_authority_delimiter(std::string_view view) noexcept; + +/** + * @private + */ +template +inline void inner_concat(std::string &buffer, T t) { + buffer.append(t); +} + +/** + * @private + */ +template +inline void inner_concat(std::string &buffer, T t, Args... args) { + buffer.append(t); + return inner_concat(buffer, args...); +} + +/** + * @private + * Concatenate the arguments and return a string. + * @returns a string + */ +template std::string concat(Args... args) { + std::string answer; + inner_concat(answer, args...); + return answer; +} + +/** + * @private + * @return Number of leading zeroes. + */ +inline int leading_zeroes(uint32_t input_num) noexcept { +#if ADA_REGULAR_VISUAL_STUDIO + unsigned long leading_zero(0); + unsigned long in(input_num); + return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32; +#else + return __builtin_clz(input_num); +#endif // ADA_REGULAR_VISUAL_STUDIO +} + +/** + * @private + * Counts the number of decimal digits necessary to represent x. + * faster than std::to_string(x).size(). + * @return digit count + */ +inline int fast_digit_count(uint32_t x) noexcept { + auto int_log2 = [](uint32_t z) -> int { + return 31 - ada::helpers::leading_zeroes(z | 1); + }; + // Compiles to very few instructions. Note that the + // table is static and thus effectively a constant. + // We leave it inside the function because it is meaningless + // outside of it (this comes at no performance cost). + const static uint64_t table[] = { + 4294967296, 8589934582, 8589934582, 8589934582, 12884901788, + 12884901788, 12884901788, 17179868184, 17179868184, 17179868184, + 21474826480, 21474826480, 21474826480, 21474826480, 25769703776, + 25769703776, 25769703776, 30063771072, 30063771072, 30063771072, + 34349738368, 34349738368, 34349738368, 34349738368, 38554705664, + 38554705664, 38554705664, 41949672960, 41949672960, 41949672960, + 42949672960, 42949672960}; + return int((x + table[int_log2(x)]) >> 32); +} +} // namespace ada::helpers + +#endif // ADA_HELPERS_H +/* end file include/ada/helpers.h */ +/* begin file include/ada/parser.h */ +/** + * @file parser.h + * @brief Definitions for the parser. + */ +#ifndef ADA_PARSER_H +#define ADA_PARSER_H + +#include +#include + +/* begin file include/ada/expected.h */ +/** + * @file expected.h + * @brief Definitions for std::expected + * @private Excluded from docs through the doxygen file. + */ +/// +// expected - An implementation of std::expected with extensions +// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) +// +// Documentation available at http://tl.tartanllama.xyz/ +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to the +// public domain worldwide. This software is distributed without any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. If not, see +// . +/// + +#ifndef TL_EXPECTED_HPP +#define TL_EXPECTED_HPP + +#define TL_EXPECTED_VERSION_MAJOR 1 +#define TL_EXPECTED_VERSION_MINOR 1 +#define TL_EXPECTED_VERSION_PATCH 0 + +#include +#include +#include +#include + +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) +#define TL_EXPECTED_EXCEPTIONS_ENABLED +#endif + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define TL_EXPECTED_MSVC2015 +#define TL_EXPECTED_MSVC2015_CONSTEXPR +#else +#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC55 +#endif + +#if !defined(TL_ASSERT) +// can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug +#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49) +#include +#define TL_ASSERT(x) assert(x) +#else +#define TL_ASSERT(x) +#endif +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +// GCC < 5 doesn't support overloading on const&& for member functions + +#define TL_EXPECTED_NO_CONSTRR +// GCC < 5 doesn't support some standard C++11 type traits +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::has_trivial_copy_constructor +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::has_trivial_copy_assign + +// This one will be different for GCC 5.7 if it's ever supported +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible + +// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks +// std::vector for non-copyable types +#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) +#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace tl { +namespace detail { +template +struct is_trivially_copy_constructible + : std::is_trivially_copy_constructible {}; +#ifdef _GLIBCXX_VECTOR +template +struct is_trivially_copy_constructible> : std::false_type {}; +#endif +} // namespace detail +} // namespace tl +#endif + +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + tl::detail::is_trivially_copy_constructible +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible +#else +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::is_trivially_copy_constructible +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible +#endif + +#if __cplusplus > 201103L +#define TL_EXPECTED_CXX14 +#endif + +#ifdef TL_EXPECTED_GCC49 +#define TL_EXPECTED_GCC49_CONSTEXPR +#else +#define TL_EXPECTED_GCC49_CONSTEXPR constexpr +#endif + +#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \ + defined(TL_EXPECTED_GCC49)) +#define TL_EXPECTED_11_CONSTEXPR +#else +#define TL_EXPECTED_11_CONSTEXPR constexpr +#endif + +namespace tl { +template class expected; + +#ifndef TL_MONOSTATE_INPLACE_MUTEX +#define TL_MONOSTATE_INPLACE_MUTEX +class monostate {}; + +struct in_place_t { + explicit in_place_t() = default; +}; +static constexpr in_place_t in_place{}; +#endif + +template class unexpected { +public: + static_assert(!std::is_same::value, "E must not be void"); + + unexpected() = delete; + constexpr explicit unexpected(const E &e) : m_val(e) {} + + constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {} + + template ::value>::type * = nullptr> + constexpr explicit unexpected(Args &&...args) + : m_val(std::forward(args)...) {} + template < + class U, class... Args, + typename std::enable_if &, Args &&...>::value>::type * = nullptr> + constexpr explicit unexpected(std::initializer_list l, Args &&...args) + : m_val(l, std::forward(args)...) {} + + constexpr const E &value() const & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); } + constexpr const E &&value() const && { return std::move(m_val); } + +private: + E m_val; +}; + +#ifdef __cpp_deduction_guides +template unexpected(E) -> unexpected; +#endif + +template +constexpr bool operator==(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() == rhs.value(); +} +template +constexpr bool operator!=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() != rhs.value(); +} +template +constexpr bool operator<(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() < rhs.value(); +} +template +constexpr bool operator<=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() <= rhs.value(); +} +template +constexpr bool operator>(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() > rhs.value(); +} +template +constexpr bool operator>=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() >= rhs.value(); +} + +template +unexpected::type> make_unexpected(E &&e) { + return unexpected::type>(std::forward(e)); +} + +struct unexpect_t { + unexpect_t() = default; +}; +static constexpr unexpect_t unexpect{}; + +namespace detail { +template +[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) { +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + throw std::forward(e); +#else + (void)e; +#ifdef _MSC_VER + __assume(0); +#else + __builtin_unreachable(); +#endif +#endif +} + +#ifndef TL_TRAITS_MUTEX +#define TL_TRAITS_MUTEX +// C++14-style aliases for brevity +template using remove_const_t = typename std::remove_const::type; +template +using remove_reference_t = typename std::remove_reference::type; +template using decay_t = typename std::decay::type; +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; + +// std::conjunction from C++17 +template struct conjunction : std::true_type {}; +template struct conjunction : B {}; +template +struct conjunction + : std::conditional, B>::type {}; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +#endif + +// In C++11 mode, there's an issue in libc++'s std::mem_fn +// which results in a hard-error when using it in a noexcept expression +// in some cases. This is a check to workaround the common failing case. +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +template +struct is_pointer_to_non_const_member_func : std::false_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; + +template struct is_const_or_const_ref : std::false_type {}; +template struct is_const_or_const_ref : std::true_type {}; +template struct is_const_or_const_ref : std::true_type {}; +#endif + +// std::invoke from C++17 +// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround +template < + typename Fn, typename... Args, +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t::value && + is_const_or_const_ref::value)>, +#endif + typename = enable_if_t>::value>, int = 0> +constexpr auto invoke(Fn &&f, Args &&...args) noexcept( + noexcept(std::mem_fn(f)(std::forward(args)...))) + -> decltype(std::mem_fn(f)(std::forward(args)...)) { + return std::mem_fn(f)(std::forward(args)...); +} + +template >::value>> +constexpr auto invoke(Fn &&f, Args &&...args) noexcept( + noexcept(std::forward(f)(std::forward(args)...))) + -> decltype(std::forward(f)(std::forward(args)...)) { + return std::forward(f)(std::forward(args)...); +} + +// std::invoke_result from C++17 +template struct invoke_result_impl; + +template +struct invoke_result_impl< + F, + decltype(detail::invoke(std::declval(), std::declval()...), void()), + Us...> { + using type = + decltype(detail::invoke(std::declval(), std::declval()...)); +}; + +template +using invoke_result = invoke_result_impl; + +template +using invoke_result_t = typename invoke_result::type; + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +// TODO make a version which works with MSVC 2015 +template struct is_swappable : std::true_type {}; + +template struct is_nothrow_swappable : std::true_type {}; +#else +// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept +namespace swap_adl_tests { +// if swap ADL finds this then it would call std::swap otherwise (same +// signature) +struct tag {}; + +template tag swap(T &, T &); +template tag swap(T (&a)[N], T (&b)[N]); + +// helper functions to test if an unqualified swap is possible, and if it +// becomes std::swap +template std::false_type can_swap(...) noexcept(false); +template (), std::declval()))> +std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), + std::declval()))); + +template std::false_type uses_std(...); +template +std::is_same(), std::declval())), tag> +uses_std(int); + +template +struct is_std_swap_noexcept + : std::integral_constant::value && + std::is_nothrow_move_assignable::value> {}; + +template +struct is_std_swap_noexcept : is_std_swap_noexcept {}; + +template +struct is_adl_swap_noexcept + : std::integral_constant(0))> {}; +} // namespace swap_adl_tests + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + (std::is_move_assignable::value && + std::is_move_constructible::value))> {}; + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std( + 0))::value || + is_swappable::value)> {}; + +template +struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable::value && + ((decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_std_swap_noexcept::value) || + (!decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept::value))> {}; +#endif +#endif + +// Trait for checking if a type is a tl::expected +template struct is_expected_impl : std::false_type {}; +template +struct is_expected_impl> : std::true_type {}; +template using is_expected = is_expected_impl>; + +template +using expected_enable_forward_value = detail::enable_if_t< + std::is_constructible::value && + !std::is_same, in_place_t>::value && + !std::is_same, detail::decay_t>::value && + !std::is_same, detail::decay_t>::value>; + +template +using expected_enable_from_other = detail::enable_if_t< + std::is_constructible::value && + std::is_constructible::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value>; + +template +using is_void_or = conditional_t::value, std::true_type, U>; + +template +using is_copy_constructible_or_void = + is_void_or>; + +template +using is_move_constructible_or_void = + is_void_or>; + +template +using is_copy_assignable_or_void = is_void_or>; + +template +using is_move_assignable_or_void = is_void_or>; + +} // namespace detail + +namespace detail { +struct no_init_t {}; +static constexpr no_init_t no_init{}; + +// Implements the storage of the values, and ensures that the destructor is +// trivial if it can be. +// +// This specialization is for where neither `T` or `E` is trivially +// destructible, so the destructors must be called on destruction of the +// `expected` +template ::value, + bool = std::is_trivially_destructible::value> +struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } else { + m_unexpect.~unexpected(); + } + } + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// This specialization is for when both `T` and `E` are trivially-destructible, +// so the destructor of the `expected` can be trivial. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() = default; + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// T is trivial, E is not. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t) + : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected(); + } + } + + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// E is trivial, T is not. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } + } + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is trivially-destructible +template struct expected_storage_base { +#if __GNUC__ <= 5 +// no constexpr for GCC 4/5 bug +#else + TL_EXPECTED_MSVC2015_CONSTEXPR +#endif + expected_storage_base() : m_has_val(true) {} + + constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_has_val(true) {} + + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() = default; + struct dummy {}; + union { + unexpected m_unexpect; + dummy m_val; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is not trivially-destructible +template struct expected_storage_base { + constexpr expected_storage_base() : m_dummy(), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {} + + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected(); + } + } + + union { + unexpected m_unexpect; + char m_dummy; + }; + bool m_has_val; +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct expected_operations_base : expected_storage_base { + using expected_storage_base::expected_storage_base; + + template void construct(Args &&...args) noexcept { + new (std::addressof(this->m_val)) T(std::forward(args)...); + this->m_has_val = true; + } + + template void construct_with(Rhs &&rhs) noexcept { + new (std::addressof(this->m_val)) T(std::forward(rhs).get()); + this->m_has_val = true; + } + + template void construct_error(Args &&...args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected(std::forward(args)...); + this->m_has_val = false; + } + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + + // These assign overloads ensure that the most efficient assignment + // implementation is used while maintaining the strong exception guarantee. + // The problematic case is where rhs has a value, but *this does not. + // + // This overload handles the case where we can just copy-construct `T` + // directly into place without throwing. + template ::value> + * = nullptr> + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + // This overload handles the case where we can attempt to create a copy of + // `T`, then no-throw move it into place if the copy was successful. + template ::value && + std::is_nothrow_move_constructible::value> + * = nullptr> + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + T tmp = rhs.get(); + geterr().~unexpected(); + construct(std::move(tmp)); + } else { + assign_common(rhs); + } + } + + // This overload is the worst-case, where we have to move-construct the + // unexpected value into temporary storage, then try to copy the T into place. + // If the construction succeeds, then everything is fine, but if it throws, + // then we move the old unexpected value back into place before rethrowing the + // exception. + template ::value && + !std::is_nothrow_move_constructible::value> + * = nullptr> + void assign(const expected_operations_base &rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(rhs.get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(rhs.get()); +#endif + } else { + assign_common(rhs); + } + } + + // These overloads do the same as above, but for rvalues + template ::value> + * = nullptr> + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + + template ::value> + * = nullptr> + void assign(expected_operations_base &&rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(std::move(rhs).get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(std::move(rhs).get()); +#endif + } else { + assign_common(std::move(rhs)); + } + } + +#else + + // If exceptions are disabled then we can just copy-construct + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + +#endif + + // The common part of move/copy assigning + template void assign_common(Rhs &&rhs) { + if (this->m_has_val) { + if (rhs.m_has_val) { + get() = std::forward(rhs).get(); + } else { + destroy_val(); + construct_error(std::forward(rhs).geterr()); + } + } else { + if (!rhs.m_has_val) { + geterr() = std::forward(rhs).geterr(); + } + } + } + + bool has_value() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; } + constexpr const T &get() const & { return this->m_val; } + TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const T &&get() const && { return std::move(this->m_val); } +#endif + + TL_EXPECTED_11_CONSTEXPR unexpected &geterr() & { + return this->m_unexpect; + } + constexpr const unexpected &geterr() const & { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected &&geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected &&geterr() const && { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); } +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct expected_operations_base : expected_storage_base { + using expected_storage_base::expected_storage_base; + + template void construct() noexcept { this->m_has_val = true; } + + // This function doesn't use its argument, but needs it so that code in + // levels above this can work independently of whether T is void + template void construct_with(Rhs &&) noexcept { + this->m_has_val = true; + } + + template void construct_error(Args &&...args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected(std::forward(args)...); + this->m_has_val = false; + } + + template void assign(Rhs &&rhs) noexcept { + if (!this->m_has_val) { + if (rhs.m_has_val) { + geterr().~unexpected(); + construct(); + } else { + geterr() = std::forward(rhs).geterr(); + } + } else { + if (!rhs.m_has_val) { + construct_error(std::forward(rhs).geterr()); + } + } + } + + bool has_value() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR unexpected &geterr() & { + return this->m_unexpect; + } + constexpr const unexpected &geterr() const & { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected &&geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected &&geterr() const && { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { + // no-op + } +}; + +// This class manages conditionally having a trivial copy constructor +// This specialization is for when T and E are trivially copy constructible +template ::value && + TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value> +struct expected_copy_base : expected_operations_base { + using expected_operations_base::expected_operations_base; +}; + +// This specialization is for when T or E are not trivially copy constructible +template +struct expected_copy_base : expected_operations_base { + using expected_operations_base::expected_operations_base; + + expected_copy_base() = default; + expected_copy_base(const expected_copy_base &rhs) + : expected_operations_base(no_init) { + if (rhs.has_value()) { + this->construct_with(rhs); + } else { + this->construct_error(rhs.geterr()); + } + } + + expected_copy_base(expected_copy_base &&rhs) = default; + expected_copy_base &operator=(const expected_copy_base &rhs) = default; + expected_copy_base &operator=(expected_copy_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move constructor +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_constructible. We +// have to make do with a non-trivial move constructor even if T is trivially +// move constructible +#ifndef TL_EXPECTED_GCC49 +template >::value && + std::is_trivially_move_constructible::value> +struct expected_move_base : expected_copy_base { + using expected_copy_base::expected_copy_base; +}; +#else +template struct expected_move_base; +#endif +template +struct expected_move_base : expected_copy_base { + using expected_copy_base::expected_copy_base; + + expected_move_base() = default; + expected_move_base(const expected_move_base &rhs) = default; + + expected_move_base(expected_move_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value) + : expected_copy_base(no_init) { + if (rhs.has_value()) { + this->construct_with(std::move(rhs)); + } else { + this->construct_error(std::move(rhs.geterr())); + } + } + expected_move_base &operator=(const expected_move_base &rhs) = default; + expected_move_base &operator=(expected_move_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial copy assignment operator +template < + class T, class E, + bool = + is_void_or< + T, conjunction>::value && + TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value && + TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value && + TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value> +struct expected_copy_assign_base : expected_move_base { + using expected_move_base::expected_move_base; +}; + +template +struct expected_copy_assign_base : expected_move_base { + using expected_move_base::expected_move_base; + + expected_copy_assign_base() = default; + expected_copy_assign_base(const expected_copy_assign_base &rhs) = default; + + expected_copy_assign_base(expected_copy_assign_base &&rhs) = default; + expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) { + this->assign(rhs); + return *this; + } + expected_copy_assign_base & + operator=(expected_copy_assign_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move assignment operator +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_assignable. We have +// to make do with a non-trivial move assignment operator even if T is trivially +// move assignable +#ifndef TL_EXPECTED_GCC49 +template < + class T, class E, + bool = is_void_or< + T, conjunction, + std::is_trivially_move_constructible, + std::is_trivially_move_assignable>>::value && + std::is_trivially_destructible::value && + std::is_trivially_move_constructible::value && + std::is_trivially_move_assignable::value> +struct expected_move_assign_base : expected_copy_assign_base { + using expected_copy_assign_base::expected_copy_assign_base; +}; +#else +template struct expected_move_assign_base; +#endif + +template +struct expected_move_assign_base + : expected_copy_assign_base { + using expected_copy_assign_base::expected_copy_assign_base; + + expected_move_assign_base() = default; + expected_move_assign_base(const expected_move_assign_base &rhs) = default; + + expected_move_assign_base(expected_move_assign_base &&rhs) = default; + + expected_move_assign_base & + operator=(const expected_move_assign_base &rhs) = default; + + expected_move_assign_base & + operator=(expected_move_assign_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_assignable::value) { + this->assign(std::move(rhs)); + return *this; + } +}; + +// expected_delete_ctor_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible +template ::value && + std::is_copy_constructible::value), + bool EnableMove = (is_move_constructible_or_void::value && + std::is_move_constructible::value)> +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +// expected_delete_assign_base will conditionally delete copy and move +// constructors depending on whether T and E are copy/move constructible + +// assignable +template ::value && + std::is_copy_constructible::value && + is_copy_assignable_or_void::value && + std::is_copy_assignable::value), + bool EnableMove = (is_move_constructible_or_void::value && + std::is_move_constructible::value && + is_move_assignable_or_void::value && + std::is_move_assignable::value)> +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = default; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = default; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = default; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = delete; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = delete; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = default; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = delete; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = delete; +}; + +// This is needed to be able to construct the expected_default_ctor_base which +// follows, while still conditionally deleting the default constructor. +struct default_constructor_tag { + explicit constexpr default_constructor_tag() = default; +}; + +// expected_default_ctor_base will ensure that expected has a deleted default +// consturctor if T is not default constructible. +// This specialization is for when T is default constructible +template ::value || std::is_void::value> +struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = default; + constexpr expected_default_ctor_base( + expected_default_ctor_base const &) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = + default; + expected_default_ctor_base & + operator=(expected_default_ctor_base const &) noexcept = default; + expected_default_ctor_base & + operator=(expected_default_ctor_base &&) noexcept = default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; + +// This specialization is for when T is not default constructible +template struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = delete; + constexpr expected_default_ctor_base( + expected_default_ctor_base const &) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = + default; + expected_default_ctor_base & + operator=(expected_default_ctor_base const &) noexcept = default; + expected_default_ctor_base & + operator=(expected_default_ctor_base &&) noexcept = default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; +} // namespace detail + +template class bad_expected_access : public std::exception { +public: + explicit bad_expected_access(E e) : m_val(std::move(e)) {} + + virtual const char *what() const noexcept override { + return "Bad expected access"; + } + + const E &error() const & { return m_val; } + E &error() & { return m_val; } + const E &&error() const && { return std::move(m_val); } + E &&error() && { return std::move(m_val); } + +private: + E m_val; +}; + +/// An `expected` object is an object that contains the storage for +/// another object and manages the lifetime of this contained object `T`. +/// Alternatively it could contain the storage for another unexpected object +/// `E`. The contained object may not be initialized after the expected object +/// has been initialized, and may not be destroyed before the expected object +/// has been destroyed. The initialization state of the contained object is +/// tracked by the expected object. +template +class expected : private detail::expected_move_assign_base, + private detail::expected_delete_ctor_base, + private detail::expected_delete_assign_base, + private detail::expected_default_ctor_base { + static_assert(!std::is_reference::value, "T must not be a reference"); + static_assert(!std::is_same::type>::value, + "T must not be in_place_t"); + static_assert(!std::is_same::type>::value, + "T must not be unexpect_t"); + static_assert( + !std::is_same>::type>::value, + "T must not be unexpected"); + static_assert(!std::is_reference::value, "E must not be a reference"); + + T *valptr() { return std::addressof(this->m_val); } + const T *valptr() const { return std::addressof(this->m_val); } + unexpected *errptr() { return std::addressof(this->m_unexpect); } + const unexpected *errptr() const { + return std::addressof(this->m_unexpect); + } + + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &val() { + return this->m_val; + } + TL_EXPECTED_11_CONSTEXPR unexpected &err() { return this->m_unexpect; } + + template ::value> * = nullptr> + constexpr const U &val() const { + return this->m_val; + } + constexpr const unexpected &err() const { return this->m_unexpect; } + + using impl_base = detail::expected_move_assign_base; + using ctor_base = detail::expected_default_ctor_base; + +public: + typedef T value_type; + typedef E error_type; + typedef unexpected unexpected_type; + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & { + return and_then_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && { + return and_then_impl(std::move(*this), std::forward(f)); + } + template constexpr auto and_then(F &&f) const & { + return and_then_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template constexpr auto and_then(F &&f) const && { + return and_then_impl(std::move(*this), std::forward(f)); + } +#endif + +#else + template + TL_EXPECTED_11_CONSTEXPR auto + and_then(F &&f) & -> decltype(and_then_impl(std::declval(), + std::forward(f))) { + return and_then_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto + and_then(F &&f) && -> decltype(and_then_impl(std::declval(), + std::forward(f))) { + return and_then_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto and_then(F &&f) const & -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr auto and_then(F &&f) const && -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template constexpr auto map(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + template constexpr auto map(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval(), std::declval())) + map(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template constexpr auto transform(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + template constexpr auto transform(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval(), std::declval())) + transform(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template constexpr auto map_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + template constexpr auto map_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#endif +#endif +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template constexpr auto transform_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + template constexpr auto transform_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + template expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & { + return or_else_impl(*this, std::forward(f)); + } + + template expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && { + return or_else_impl(std::move(*this), std::forward(f)); + } + + template expected constexpr or_else(F &&f) const & { + return or_else_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template expected constexpr or_else(F &&f) const && { + return or_else_impl(std::move(*this), std::forward(f)); + } +#endif + constexpr expected() = default; + constexpr expected(const expected &rhs) = default; + constexpr expected(expected &&rhs) = default; + expected &operator=(const expected &rhs) = default; + expected &operator=(expected &&rhs) = default; + + template ::value> * = + nullptr> + constexpr expected(in_place_t, Args &&...args) + : impl_base(in_place, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected(in_place_t, std::initializer_list il, Args &&...args) + : impl_base(in_place, il, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value> * = + nullptr, + detail::enable_if_t::value> * = + nullptr> + explicit constexpr expected(const unexpected &e) + : impl_base(unexpect, e.value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr> + constexpr expected(unexpected const &e) + : impl_base(unexpect, e.value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> + explicit constexpr expected(unexpected &&e) noexcept( + std::is_nothrow_constructible::value) + : impl_base(unexpect, std::move(e.value())), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> + constexpr expected(unexpected &&e) noexcept( + std::is_nothrow_constructible::value) + : impl_base(unexpect, std::move(e.value())), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value> * = + nullptr> + constexpr explicit expected(unexpect_t, Args &&...args) + : impl_base(unexpect, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected(unexpect_t, std::initializer_list il, + Args &&...args) + : impl_base(unexpect, il, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value && + std::is_convertible::value)> * = + nullptr, + detail::expected_enable_from_other + * = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(const expected &rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.error()); + } + } + + template ::value && + std::is_convertible::value)> * = + nullptr, + detail::expected_enable_from_other + * = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(const expected &rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.error()); + } + } + + template < + class U, class G, + detail::enable_if_t::value && + std::is_convertible::value)> * = nullptr, + detail::expected_enable_from_other * = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(expected &&rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.error())); + } + } + + template < + class U, class G, + detail::enable_if_t<(std::is_convertible::value && + std::is_convertible::value)> * = nullptr, + detail::expected_enable_from_other * = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(expected &&rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.error())); + } + } + + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::expected_enable_forward_value * = nullptr> + explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) + : expected(in_place, std::forward(v)) {} + + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::expected_enable_forward_value * = nullptr> + TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) + : expected(in_place, std::forward(v)) {} + + template < + class U = T, class G = T, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t< + (!std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && + std::is_assignable::value && + std::is_nothrow_move_constructible::value)> * = nullptr> + expected &operator=(U &&v) { + if (has_value()) { + val() = std::forward(v); + } else { + err().~unexpected(); + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; + } + + return *this; + } + + template < + class U = T, class G = T, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t< + (!std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && + std::is_assignable::value && + std::is_nothrow_move_constructible::value)> * = nullptr> + expected &operator=(U &&v) { + if (has_value()) { + val() = std::forward(v); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; +#endif + } + + return *this; + } + + template ::value && + std::is_assignable::value> * = nullptr> + expected &operator=(const unexpected &rhs) { + if (!has_value()) { + err() = rhs; + } else { + this->destroy_val(); + ::new (errptr()) unexpected(rhs); + this->m_has_val = false; + } + + return *this; + } + + template ::value && + std::is_move_assignable::value> * = nullptr> + expected &operator=(unexpected &&rhs) noexcept { + if (!has_value()) { + err() = std::move(rhs); + } else { + this->destroy_val(); + ::new (errptr()) unexpected(std::move(rhs)); + this->m_has_val = false; + } + + return *this; + } + + template ::value> * = nullptr> + void emplace(Args &&...args) { + if (has_value()) { + val().~T(); + } else { + err().~unexpected(); + this->m_has_val = true; + } + ::new (valptr()) T(std::forward(args)...); + } + + template ::value> * = nullptr> + void emplace(Args &&...args) { + if (has_value()) { + val().~T(); + ::new (valptr()) T(std::forward(args)...); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; +#endif + } + } + + template &, Args &&...>::value> * = nullptr> + void emplace(std::initializer_list il, Args &&...args) { + if (has_value()) { + T t(il, std::forward(args)...); + val() = std::move(t); + } else { + err().~unexpected(); + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + } + } + + template &, Args &&...>::value> * = nullptr> + void emplace(std::initializer_list il, Args &&...args) { + if (has_value()) { + T t(il, std::forward(args)...); + val() = std::move(t); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; +#endif + } + } + +private: + using t_is_void = std::true_type; + using t_is_not_void = std::false_type; + using t_is_nothrow_move_constructible = std::true_type; + using move_constructing_t_can_throw = std::false_type; + using e_is_nothrow_move_constructible = std::true_type; + using move_constructing_e_can_throw = std::false_type; + + void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept { + // swapping void is a no-op + } + + void swap_where_both_have_value(expected &rhs, t_is_not_void) { + using std::swap; + swap(val(), rhs.val()); + } + + void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept( + std::is_nothrow_move_constructible::value) { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value(expected &rhs, t_is_not_void) { + swap_where_only_one_has_value_and_t_is_not_void( + rhs, typename std::is_nothrow_move_constructible::type{}, + typename std::is_nothrow_move_constructible::type{}); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, t_is_nothrow_move_constructible, + e_is_nothrow_move_constructible) noexcept { + auto temp = std::move(val()); + val().~T(); + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, t_is_nothrow_move_constructible, + move_constructing_e_can_throw) { + auto temp = std::move(val()); + val().~T(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + val() = std::move(temp); + throw; + } +#else + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, move_constructing_t_can_throw, + e_is_nothrow_move_constructible) { + auto temp = std::move(rhs.err()); + rhs.err().~unexpected_type(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + rhs.err() = std::move(temp); + throw; + } +#else + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + +public: + template + detail::enable_if_t::value && + detail::is_swappable::value && + (std::is_nothrow_move_constructible::value || + std::is_nothrow_move_constructible::value)> + swap(expected &rhs) noexcept(std::is_nothrow_move_constructible::value && + detail::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && + detail::is_nothrow_swappable::value) { + if (has_value() && rhs.has_value()) { + swap_where_both_have_value(rhs, typename std::is_void::type{}); + } else if (!has_value() && rhs.has_value()) { + rhs.swap(*this); + } else if (has_value()) { + swap_where_only_one_has_value(rhs, typename std::is_void::type{}); + } else { + using std::swap; + swap(err(), rhs.err()); + } + } + + constexpr const T *operator->() const { + TL_ASSERT(has_value()); + return valptr(); + } + TL_EXPECTED_11_CONSTEXPR T *operator->() { + TL_ASSERT(has_value()); + return valptr(); + } + + template ::value> * = nullptr> + constexpr const U &operator*() const & { + TL_ASSERT(has_value()); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &operator*() & { + TL_ASSERT(has_value()); + return val(); + } + template ::value> * = nullptr> + constexpr const U &&operator*() const && { + TL_ASSERT(has_value()); + return std::move(val()); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &&operator*() && { + TL_ASSERT(has_value()); + return std::move(val()); + } + + constexpr bool has_value() const noexcept { return this->m_has_val; } + constexpr explicit operator bool() const noexcept { return this->m_has_val; } + + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR const U &value() const & { + if (!has_value()) + detail::throw_exception(bad_expected_access(err().value())); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &value() & { + if (!has_value()) + detail::throw_exception(bad_expected_access(err().value())); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR const U &&value() const && { + if (!has_value()) + detail::throw_exception(bad_expected_access(std::move(err()).value())); + return std::move(val()); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &&value() && { + if (!has_value()) + detail::throw_exception(bad_expected_access(std::move(err()).value())); + return std::move(val()); + } + + constexpr const E &error() const & { + TL_ASSERT(!has_value()); + return err().value(); + } + TL_EXPECTED_11_CONSTEXPR E &error() & { + TL_ASSERT(!has_value()); + return err().value(); + } + constexpr const E &&error() const && { + TL_ASSERT(!has_value()); + return std::move(err().value()); + } + TL_EXPECTED_11_CONSTEXPR E &&error() && { + TL_ASSERT(!has_value()); + return std::move(err().value()); + } + + template constexpr T value_or(U &&v) const & { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy-constructible and convertible to from U&&"); + return bool(*this) ? **this : static_cast(std::forward(v)); + } + template TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move-constructible and convertible to from U&&"); + return bool(*this) ? std::move(**this) : static_cast(std::forward(v)); + } +}; + +namespace detail { +template using exp_t = typename detail::decay_t::value_type; +template using err_t = typename detail::decay_t::error_type; +template using ret_t = expected>; + +#ifdef TL_EXPECTED_CXX14 +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval()))> +constexpr auto and_then_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() + ? detail::invoke(std::forward(f), *std::forward(exp)) + : Ret(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval()))> +constexpr auto and_then_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() ? detail::invoke(std::forward(f)) + : Ret(unexpect, std::forward(exp).error()); +} +#else +template struct TC; +template (), + *std::declval())), + detail::enable_if_t>::value> * = nullptr> +auto and_then_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() + ? detail::invoke(std::forward(f), *std::forward(exp)) + : Ret(unexpect, std::forward(exp).error()); +} + +template ())), + detail::enable_if_t>::value> * = nullptr> +constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() ? detail::invoke(std::forward(f)) + : Ret(unexpect, std::forward(exp).error()); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto expected_map_impl(Exp &&exp, F &&f) { + using result = ret_t>; + return exp.has_value() ? result(detail::invoke(std::forward(f), + *std::forward(exp))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +auto expected_map_impl(Exp &&exp, F &&f) { + using result = expected>; + if (exp.has_value()) { + detail::invoke(std::forward(f), *std::forward(exp)); + return result(); + } + + return result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto expected_map_impl(Exp &&exp, F &&f) { + using result = ret_t>; + return exp.has_value() ? result(detail::invoke(std::forward(f))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> +auto expected_map_impl(Exp &&exp, F &&f) { + using result = expected>; + if (exp.has_value()) { + detail::invoke(std::forward(f)); + return result(); + } + + return result(unexpect, std::forward(exp).error()); +} +#else +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto expected_map_impl(Exp &&exp, F &&f) + -> ret_t> { + using result = ret_t>; + + return exp.has_value() ? result(detail::invoke(std::forward(f), + *std::forward(exp))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto expected_map_impl(Exp &&exp, F &&f) -> expected> { + if (exp.has_value()) { + detail::invoke(std::forward(f), *std::forward(exp)); + return {}; + } + + return unexpected>(std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto expected_map_impl(Exp &&exp, F &&f) + -> ret_t> { + using result = ret_t>; + + return exp.has_value() ? result(detail::invoke(std::forward(f))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto expected_map_impl(Exp &&exp, F &&f) -> expected> { + if (exp.has_value()) { + detail::invoke(std::forward(f)); + return {}; + } + + return unexpected>(std::forward(exp).error()); +} +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, detail::decay_t>; + return exp.has_value() + ? result(*std::forward(exp)) + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, detail::decay_t>; + return exp.has_value() + ? result() + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +#else +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) + -> expected, detail::decay_t> { + using result = expected, detail::decay_t>; + + return exp.has_value() + ? result(*std::forward(exp)) + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) + -> expected, detail::decay_t> { + using result = expected, detail::decay_t>; + + return exp.has_value() + ? result() + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto or_else_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + return exp.has_value() ? std::forward(exp) + : detail::invoke(std::forward(f), + std::forward(exp).error()); +} + +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +detail::decay_t or_else_impl(Exp &&exp, F &&f) { + return exp.has_value() ? std::forward(exp) + : (detail::invoke(std::forward(f), + std::forward(exp).error()), + std::forward(exp)); +} +#else +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto or_else_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + return exp.has_value() ? std::forward(exp) + : detail::invoke(std::forward(f), + std::forward(exp).error()); +} + +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +detail::decay_t or_else_impl(Exp &&exp, F &&f) { + return exp.has_value() ? std::forward(exp) + : (detail::invoke(std::forward(f), + std::forward(exp).error()), + std::forward(exp)); +} +#endif +} // namespace detail + +template +constexpr bool operator==(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? false + : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs); +} +template +constexpr bool operator!=(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? true + : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs); +} +template +constexpr bool operator==(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? false + : (!lhs.has_value() ? lhs.error() == rhs.error() : true); +} +template +constexpr bool operator!=(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? true + : (!lhs.has_value() ? lhs.error() == rhs.error() : false); +} + +template +constexpr bool operator==(const expected &x, const U &v) { + return x.has_value() ? *x == v : false; +} +template +constexpr bool operator==(const U &v, const expected &x) { + return x.has_value() ? *x == v : false; +} +template +constexpr bool operator!=(const expected &x, const U &v) { + return x.has_value() ? *x != v : true; +} +template +constexpr bool operator!=(const U &v, const expected &x) { + return x.has_value() ? *x != v : true; +} + +template +constexpr bool operator==(const expected &x, const unexpected &e) { + return x.has_value() ? false : x.error() == e.value(); +} +template +constexpr bool operator==(const unexpected &e, const expected &x) { + return x.has_value() ? false : x.error() == e.value(); +} +template +constexpr bool operator!=(const expected &x, const unexpected &e) { + return x.has_value() ? true : x.error() != e.value(); +} +template +constexpr bool operator!=(const unexpected &e, const expected &x) { + return x.has_value() ? true : x.error() != e.value(); +} + +template ::value || + std::is_move_constructible::value) && + detail::is_swappable::value && + std::is_move_constructible::value && + detail::is_swappable::value> * = nullptr> +void swap(expected &lhs, + expected &rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); +} +} // namespace tl + +#endif +/* end file include/ada/expected.h */ +/* begin file include/ada/url_pattern_regex.h */ +/** + * @file url_search_params.h + * @brief Declaration for the URL Search Params + */ +#ifndef ADA_URL_PATTERN_REGEX_H +#define ADA_URL_PATTERN_REGEX_H + +#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER +#include +#endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER + +namespace ada::url_pattern_regex { + +template +concept regex_concept = requires(T t, std::string_view pattern, + bool ignore_case, std::string_view input) { + // Ensure the class has a type alias 'regex_type' + typename T::regex_type; + + // Function to create a regex instance + { + T::create_instance(pattern, ignore_case) + } -> std::same_as>; + + // Function to perform regex search + { + T::regex_search(input, std::declval()) + } -> std::same_as>>>; + + // Function to match regex pattern + { + T::regex_match(input, std::declval()) + } -> std::same_as; + + // Copy constructor + { T(std::declval()) } -> std::same_as; + + // Move constructor + { T(std::declval()) } -> std::same_as; +}; + +#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER +class std_regex_provider { +public: + std_regex_provider() = default; + using regex_type = std::regex; + static std::optional create_instance(std::string_view pattern, + bool ignore_case); + static std::optional>> + regex_search(std::string_view input, const regex_type &pattern); + static bool regex_match(std::string_view input, const regex_type &pattern); +}; +#endif // ADA_USE_UNSAFE_STD_REGEX_PROVIDER + +} // namespace ada::url_pattern_regex + +#endif // ADA_URL_PATTERN_REGEX_H +/* end file include/ada/url_pattern_regex.h */ +/* begin file include/ada/url_pattern_init.h */ +/** + * @file url_pattern_init.h + * @brief Declaration for the url_pattern_init implementation. + */ +#ifndef ADA_URL_PATTERN_INIT_H +#define ADA_URL_PATTERN_INIT_H + +/* begin file include/ada/errors.h */ +/** + * @file errors.h + * @brief Definitions for the errors. + */ +#ifndef ADA_ERRORS_H +#define ADA_ERRORS_H + +#include +namespace ada { +enum class errors : uint8_t { type_error }; +} // namespace ada +#endif // ADA_ERRORS_H +/* end file include/ada/errors.h */ + +#include +#include +#include + +#if ADA_TESTING +#include +#endif // ADA_TESTING + +namespace ada { + +// Important: C++20 allows us to use concept rather than `using` or `typedef +// and allows functions with second argument, which is optional (using either +// std::nullopt or a parameter with default value) +template +concept url_pattern_encoding_callback = requires(F f, std::string_view sv) { + { f(sv) } -> std::same_as>; +}; + +// A structure providing matching patterns for individual components +// of a URL. When a URLPattern is created, or when a URLPattern is +// used to match or test against a URL, the input can be given as +// either a string or a URLPatternInit struct. If a string is given, +// it will be parsed to create a URLPatternInit. The URLPatternInit +// API is defined as part of the URLPattern specification. +struct url_pattern_init { + // @see https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit + static tl::expected + process(url_pattern_init init, std::string_view type, + std::optional protocol = std::nullopt, + std::optional username = std::nullopt, + std::optional password = std::nullopt, + std::optional hostname = std::nullopt, + std::optional port = std::nullopt, + std::optional pathname = std::nullopt, + std::optional search = std::nullopt, + std::optional hash = std::nullopt); + + // @see https://urlpattern.spec.whatwg.org/#process-protocol-for-init + static tl::expected + process_protocol(std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-username-for-init + static tl::expected + process_username(std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-password-for-init + static tl::expected + process_password(std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-hostname-for-init + static tl::expected + process_hostname(std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-port-for-init + static tl::expected + process_port(std::string_view port, std::string_view protocol, + std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-pathname-for-init + static tl::expected + process_pathname(std::string_view value, std::string_view protocol, + std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-search-for-init + static tl::expected + process_search(std::string_view value, std::string_view type); + + // @see https://urlpattern.spec.whatwg.org/#process-hash-for-init + static tl::expected process_hash(std::string_view value, + std::string_view type); + +#if ADA_TESTING + friend void PrintTo(const url_pattern_init &init, std::ostream *os) { + *os << "protocol: '" << init.protocol.value_or("undefined") << "', "; + *os << "username: '" << init.username.value_or("undefined") << "', "; + *os << "password: '" << init.password.value_or("undefined") << "', "; + *os << "hostname: '" << init.hostname.value_or("undefined") << "', "; + *os << "port: '" << init.port.value_or("undefined") << "', "; + *os << "pathname: '" << init.pathname.value_or("undefined") << "', "; + *os << "search: '" << init.search.value_or("undefined") << "', "; + *os << "hash: '" << init.hash.value_or("undefined") << "', "; + *os << "base_url: '" << init.base_url.value_or("undefined") << "', "; + } +#endif // ADA_TESTING + + bool operator==(const url_pattern_init &) const; + + std::optional protocol{}; + std::optional username{}; + std::optional password{}; + std::optional hostname{}; + std::optional port{}; + std::optional pathname{}; + std::optional search{}; + std::optional hash{}; + std::optional base_url{}; +}; +} // namespace ada + +#endif // ADA_URL_PATTERN_INIT_H +/* end file include/ada/url_pattern_init.h */ + +/** + * @private + */ +namespace ada { +struct url_aggregator; +struct url; +template class url_pattern; +struct url_pattern_options; +enum class errors : uint8_t; +} // namespace ada + +/** + * @namespace ada::parser + * @brief Includes the definitions for supported parsers + */ +namespace ada::parser { +/** + * Parses a url. The parameter user_input is the input to be parsed: + * it should be a valid UTF-8 string. The parameter base_url is an optional + * parameter that can be used to resolve relative URLs. If the base_url is + * provided, the user_input is resolved against the base_url. + */ +template +result_type parse_url(std::string_view user_input, + const result_type *base_url = nullptr); + +extern template url_aggregator +parse_url(std::string_view user_input, + const url_aggregator *base_url); +extern template url parse_url(std::string_view user_input, + const url *base_url); + +template +result_type parse_url_impl(std::string_view user_input, + const result_type *base_url = nullptr); + +extern template url_aggregator +parse_url_impl(std::string_view user_input, + const url_aggregator *base_url); +extern template url parse_url_impl(std::string_view user_input, + const url *base_url); + +template +tl::expected, errors> +parse_url_pattern_impl(std::variant input, + const std::string_view *base_url, + const url_pattern_options *options); + +} // namespace ada::parser + +#endif // ADA_PARSER_H +/* end file include/ada/parser.h */ +/* begin file include/ada/parser-inl.h */ +/** + * @file parser-inl.h + */ +#ifndef ADA_PARSER_INL_H +#define ADA_PARSER_INL_H + +/* begin file include/ada/url_pattern.h */ +/** + * @file url_pattern.h + * @brief Declaration for the URLPattern implementation. + */ +#ifndef ADA_URL_PATTERN_H +#define ADA_URL_PATTERN_H + +/* begin file include/ada/implementation.h */ +/** + * @file implementation.h + * @brief Definitions for user facing functions for parsing URL and it's + * components. + */ +#ifndef ADA_IMPLEMENTATION_H +#define ADA_IMPLEMENTATION_H + +#include +#include + +/* begin file include/ada/url.h */ +/** + * @file url.h + * @brief Declaration for the URL + */ +#ifndef ADA_URL_H +#define ADA_URL_H + +#include +#include +#include +#include + +/* begin file include/ada/checkers.h */ +/** + * @file checkers.h + * @brief Declarations for URL specific checkers used within Ada. + */ +#ifndef ADA_CHECKERS_H +#define ADA_CHECKERS_H + +#include +#include + +/** + * These functions are not part of our public API and may + * change at any time. + * @private + * @namespace ada::checkers + * @brief Includes the definitions for validation functions + */ +namespace ada::checkers { + +/** + * @private + * Assuming that x is an ASCII letter, this function returns the lower case + * equivalent. + * @details More likely to be inlined by the compiler and constexpr. + */ +constexpr char to_lower(char x) noexcept; + +/** + * @private + * Returns true if the character is an ASCII letter. Equivalent to std::isalpha + * but more likely to be inlined by the compiler. + * + * @attention std::isalpha is not constexpr generally. + */ +constexpr bool is_alpha(char x) noexcept; + +/** + * @private + * Check whether a string starts with 0x or 0X. The function is only + * safe if input.size() >=2. + * + * @see has_hex_prefix + */ +constexpr bool has_hex_prefix_unsafe(std::string_view input); +/** + * @private + * Check whether a string starts with 0x or 0X. + */ +constexpr bool has_hex_prefix(std::string_view input); + +/** + * @private + * Check whether x is an ASCII digit. More likely to be inlined than + * std::isdigit. + */ +constexpr bool is_digit(char x) noexcept; + +/** + * @private + * @details A string starts with a Windows drive letter if all of the following + * are true: + * + * - its length is greater than or equal to 2 + * - its first two code points are a Windows drive letter + * - its length is 2 or its third code point is U+002F (/), U+005C (\), U+003F + * (?), or U+0023 (#). + * + * https://url.spec.whatwg.org/#start-with-a-windows-drive-letter + */ +inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept; + +/** + * @private + * @details A normalized Windows drive letter is a Windows drive letter of which + * the second code point is U+003A (:). + */ +inline constexpr bool +is_normalized_windows_drive_letter(std::string_view input) noexcept; + +/** + * @private + * Returns true if an input is an ipv4 address. It is assumed that the string + * does not contain uppercase ASCII characters (the input should have been + * lowered cased before calling this function) and is not empty. + */ +ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept; + +/** + * @private + * Returns a bitset. If the first bit is set, then at least one character needs + * percent encoding. If the second bit is set, a \\ is found. If the third bit + * is set then we have a dot. If the fourth bit is set, then we have a percent + * character. + */ +ada_really_inline constexpr uint8_t +path_signature(std::string_view input) noexcept; + +/** + * @private + * Returns true if the length of the domain name and its labels are according to + * the specifications. The length of the domain must be 255 octets (253 + * characters not including the last 2 which are the empty label reserved at the + * end). When the empty label is included (a dot at the end), the domain name + * can have 254 characters. The length of a label must be at least 1 and at most + * 63 characters. + * @see section 3.1. of https://www.rfc-editor.org/rfc/rfc1034 + * @see https://www.unicode.org/reports/tr46/#ToASCII + */ +ada_really_inline constexpr bool +verify_dns_length(std::string_view input) noexcept; + +} // namespace ada::checkers + +#endif // ADA_CHECKERS_H +/* end file include/ada/checkers.h */ +/* begin file include/ada/url_components.h */ +/** + * @file url_components.h + * @brief Declaration for the URL Components + */ +#ifndef ADA_URL_COMPONENTS_H +#define ADA_URL_COMPONENTS_H + +namespace ada { + +/** + * @brief URL Component representations using offsets. + * + * @details We design the url_components struct so that it is as small + * and simple as possible. This version uses 32 bytes. + * + * This struct is used to extract components from a single 'href'. + */ +struct url_components { + constexpr static uint32_t omitted = uint32_t(-1); + + url_components() = default; + url_components(const url_components &u) = default; + url_components(url_components &&u) noexcept = default; + url_components &operator=(url_components &&u) noexcept = default; + url_components &operator=(const url_components &u) = default; + ~url_components() = default; + + /* + * By using 32-bit integers, we implicitly assume that the URL string + * cannot exceed 4 GB. + * + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + */ + uint32_t protocol_end{0}; + /** + * Username end is not `omitted` by default to make username and password + * getters less costly to implement. + */ + uint32_t username_end{0}; + uint32_t host_start{0}; + uint32_t host_end{0}; + uint32_t port{omitted}; + uint32_t pathname_start{0}; + uint32_t search_start{omitted}; + uint32_t hash_start{omitted}; + + /** + * Check the following conditions: + * protocol_end < username_end < ... < hash_start, + * expect when a value is omitted. It also computes + * a lower bound on the possible string length that may match these + * offsets. + * @return true if the offset values are + * consistent with a possible URL string + */ + [[nodiscard]] constexpr bool check_offset_consistency() const noexcept; + + /** + * Converts a url_components to JSON stringified version. + */ + [[nodiscard]] std::string to_string() const; + +}; // struct url_components +} // namespace ada +#endif +/* end file include/ada/url_components.h */ + +namespace ada { + +struct url_aggregator; + +// namespace parser { +// template +// result_type parse_url(std::string_view user_input, +// const result_type* base_url = nullptr); +// template +// result_type parse_url_impl(std::string_view user_input, +// const result_type* base_url = nullptr); +// } + +/** + * @brief Generic URL struct reliant on std::string instantiation. + * + * @details To disambiguate from a valid URL string it can also be referred to + * as a URL record. A URL is a struct that represents a universal identifier. + * Unlike the url_aggregator, the ada::url represents the different components + * of a parsed URL as independent std::string instances. This makes the + * structure heavier and more reliant on memory allocations. When getting + * components from the parsed URL, a new std::string is typically constructed. + * + * @see https://url.spec.whatwg.org/#url-representation + */ +struct url : url_base { + url() = default; + url(const url &u) = default; + url(url &&u) noexcept = default; + url &operator=(url &&u) noexcept = default; + url &operator=(const url &u) = default; + ~url() override = default; + + /** + * @private + * A URL's username is an ASCII string identifying a username. It is initially + * the empty string. + */ + std::string username{}; + + /** + * @private + * A URL's password is an ASCII string identifying a password. It is initially + * the empty string. + */ + std::string password{}; + + /** + * @private + * A URL's host is null or a host. It is initially null. + */ + std::optional host{}; + + /** + * @private + * A URL's port is either null or a 16-bit unsigned integer that identifies a + * networking port. It is initially null. + */ + std::optional port{}; + + /** + * @private + * A URL's path is either an ASCII string or a list of zero or more ASCII + * strings, usually identifying a location. + */ + std::string path{}; + + /** + * @private + * A URL's query is either null or an ASCII string. It is initially null. + */ + std::optional query{}; + + /** + * @private + * A URL's fragment is either null or an ASCII string that can be used for + * further processing on the resource the URL's other components identify. It + * is initially null. + */ + std::optional hash{}; + + /** @return true if it has an host but it is the empty string */ + [[nodiscard]] inline bool has_empty_hostname() const noexcept; + /** @return true if the URL has a (non default) port */ + [[nodiscard]] inline bool has_port() const noexcept; + /** @return true if it has a host (included an empty host) */ + [[nodiscard]] inline bool has_hostname() const noexcept; + [[nodiscard]] bool has_valid_domain() const noexcept override; + + /** + * Returns a JSON string representation of this URL. + */ + [[nodiscard]] std::string to_string() const override; + + /** + * @see https://url.spec.whatwg.org/#dom-url-href + * @see https://url.spec.whatwg.org/#concept-url-serializer + */ + [[nodiscard]] ada_really_inline std::string get_href() const noexcept; + + /** + * The origin getter steps are to return the serialization of this's URL's + * origin. [HTML] + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#concept-url-origin + */ + [[nodiscard]] std::string get_origin() const noexcept override; + + /** + * The protocol getter steps are to return this's URL's scheme, followed by + * U+003A (:). + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#dom-url-protocol + */ + [[nodiscard]] std::string get_protocol() const noexcept; + + /** + * Return url's host, serialized, followed by U+003A (:) and url's port, + * serialized. + * When there is no host, this function returns the empty string. + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#dom-url-host + */ + [[nodiscard]] std::string get_host() const noexcept; + + /** + * Return this's URL's host, serialized. + * When there is no host, this function returns the empty string. + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#dom-url-hostname + */ + [[nodiscard]] std::string get_hostname() const noexcept; + + /** + * The pathname getter steps are to return the result of URL path serializing + * this's URL. + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] constexpr std::string_view get_pathname() const noexcept; + + /** + * Compute the pathname length in bytes without instantiating a view or a + * string. + * @return size of the pathname in bytes + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept; + + /** + * Return U+003F (?), followed by this's URL's query. + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#dom-url-search + */ + [[nodiscard]] std::string get_search() const noexcept; + + /** + * The username getter steps are to return this's URL's username. + * @return a constant reference to the underlying string. + * @see https://url.spec.whatwg.org/#dom-url-username + */ + [[nodiscard]] const std::string &get_username() const noexcept; + + /** + * @return Returns true on successful operation. + * @see https://url.spec.whatwg.org/#dom-url-username + */ + bool set_username(std::string_view input); + + /** + * @return Returns true on success. + * @see https://url.spec.whatwg.org/#dom-url-password + */ + bool set_password(std::string_view input); + + /** + * @return Returns true on success. + * @see https://url.spec.whatwg.org/#dom-url-port + */ + bool set_port(std::string_view input); + + /** + * This function always succeeds. + * @see https://url.spec.whatwg.org/#dom-url-hash + */ + void set_hash(std::string_view input); + + /** + * This function always succeeds. + * @see https://url.spec.whatwg.org/#dom-url-search + */ + void set_search(std::string_view input); + + /** + * @return Returns true on success. + * @see https://url.spec.whatwg.org/#dom-url-search + */ + bool set_pathname(std::string_view input); + + /** + * @return Returns true on success. + * @see https://url.spec.whatwg.org/#dom-url-host + */ + bool set_host(std::string_view input); + + /** + * @return Returns true on success. + * @see https://url.spec.whatwg.org/#dom-url-hostname + */ + bool set_hostname(std::string_view input); + + /** + * @return Returns true on success. + * @see https://url.spec.whatwg.org/#dom-url-protocol + */ + bool set_protocol(std::string_view input); + + /** + * @see https://url.spec.whatwg.org/#dom-url-href + */ + bool set_href(std::string_view input); + + /** + * The password getter steps are to return this's URL's password. + * @return a constant reference to the underlying string. + * @see https://url.spec.whatwg.org/#dom-url-password + */ + [[nodiscard]] const std::string &get_password() const noexcept; + + /** + * Return this's URL's port, serialized. + * @return a newly constructed string representing the port. + * @see https://url.spec.whatwg.org/#dom-url-port + */ + [[nodiscard]] std::string get_port() const noexcept; + + /** + * Return U+0023 (#), followed by this's URL's fragment. + * @return a newly constructed string representing the hash. + * @see https://url.spec.whatwg.org/#dom-url-hash + */ + [[nodiscard]] std::string get_hash() const noexcept; + + /** + * A URL includes credentials if its username or password is not the empty + * string. + */ + [[nodiscard]] ada_really_inline bool has_credentials() const noexcept; + + /** + * Useful for implementing efficient serialization for the URL. + * + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + * + * Inspired after servo/url + * + * @return a newly constructed component. + * + * @see + * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31 + */ + [[nodiscard]] ada_really_inline ada::url_components + get_components() const noexcept; + /** @return true if the URL has a hash component */ + [[nodiscard]] constexpr bool has_hash() const noexcept override; + /** @return true if the URL has a search component */ + [[nodiscard]] constexpr bool has_search() const noexcept override; + +private: + friend ada::url ada::parser::parse_url(std::string_view, + const ada::url *); + friend ada::url_aggregator + ada::parser::parse_url(std::string_view, + const ada::url_aggregator *); + friend void ada::helpers::strip_trailing_spaces_from_opaque_path( + ada::url &url) noexcept; + + friend ada::url ada::parser::parse_url_impl(std::string_view, + const ada::url *); + friend ada::url_aggregator + ada::parser::parse_url_impl( + std::string_view, const ada::url_aggregator *); + + inline void update_unencoded_base_hash(std::string_view input); + inline void update_base_hostname(std::string_view input); + inline void update_base_search(std::string_view input, + const uint8_t query_percent_encode_set[]); + inline void update_base_search(std::optional &&input); + inline void update_base_pathname(std::string_view input); + inline void update_base_username(std::string_view input); + inline void update_base_password(std::string_view input); + inline void update_base_port(std::optional input); + + /** + * Sets the host or hostname according to override condition. + * Return true on success. + * @see https://url.spec.whatwg.org/#hostname-state + */ + template + bool set_host_or_hostname(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-ipv4-parser + */ + [[nodiscard]] bool parse_ipv4(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-ipv6-parser + */ + [[nodiscard]] bool parse_ipv6(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-opaque-host-parser + */ + [[nodiscard]] bool parse_opaque_host(std::string_view input); + + /** + * A URL's scheme is an ASCII string that identifies the type of URL and can + * be used to dispatch a URL for further processing after parsing. It is + * initially the empty string. We only set non_special_scheme when the scheme + * is non-special, otherwise we avoid constructing string. + * + * Special schemes are stored in ada::scheme::details::is_special_list so we + * typically do not need to store them in each url instance. + */ + std::string non_special_scheme{}; + + /** + * A URL cannot have a username/password/port if its host is null or the empty + * string, or its scheme is "file". + */ + [[nodiscard]] inline bool cannot_have_credentials_or_port() const; + + ada_really_inline size_t parse_port( + std::string_view view, bool check_trailing_content) noexcept override; + + ada_really_inline size_t parse_port(std::string_view view) noexcept override { + return this->parse_port(view, false); + } + + /** + * Parse the host from the provided input. We assume that + * the input does not contain spaces or tabs. Control + * characters and spaces are not trimmed (they should have + * been removed if needed). + * Return true on success. + * @see https://url.spec.whatwg.org/#host-parsing + */ + [[nodiscard]] ada_really_inline bool parse_host(std::string_view input); + + template + [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input); + + constexpr void clear_pathname() override; + constexpr void clear_search() override; + constexpr void set_protocol_as_file(); + + /** + * Parse the path from the provided input. + * Return true on success. Control characters not + * trimmed from the ends (they should have + * been removed if needed). + * + * The input is expected to be UTF-8. + * + * @see https://url.spec.whatwg.org/ + */ + ada_really_inline void parse_path(std::string_view input); + + /** + * Set the scheme for this URL. The provided scheme should be a valid + * scheme string, be lower-cased, not contain spaces or tabs. It should + * have no spurious trailing or leading content. + */ + inline void set_scheme(std::string &&new_scheme) noexcept; + + /** + * Take the scheme from another URL. The scheme string is moved from the + * provided url. + */ + constexpr void copy_scheme(ada::url &&u) noexcept; + + /** + * Take the scheme from another URL. The scheme string is copied from the + * provided url. + */ + constexpr void copy_scheme(const ada::url &u); + +}; // struct url + +inline std::ostream &operator<<(std::ostream &out, const ada::url &u); +} // namespace ada + +#endif // ADA_URL_H +/* end file include/ada/url.h */ + +namespace ada { + +template +using result = tl::expected; + +/** + * The URL parser takes a scalar value string input, with an optional null or + * base URL base (default null). The parser assumes the input is a valid ASCII + * or UTF-8 string. + * + * @param input the string input to analyze (must be valid ASCII or UTF-8) + * @param base_url the optional URL input to use as a base url. + * @return a parsed URL. + */ +template +ada_warn_unused ada::result +parse(std::string_view input, const result_type *base_url = nullptr); + +extern template ada::result parse(std::string_view input, + const url *base_url); +extern template ada::result +parse(std::string_view input, const url_aggregator *base_url); + +/** + * Verifies whether the URL strings can be parsed. The function assumes + * that the inputs are valid ASCII or UTF-8 strings. + * @see https://url.spec.whatwg.org/#dom-url-canparse + * @return If URL can be parsed or not. + */ +bool can_parse(std::string_view input, + const std::string_view *base_input = nullptr); + +/** + * Implementation of the URL pattern parsing algorithm. + * @see https://urlpattern.spec.whatwg.org + * + * @param input valid UTF-8 string or URLPatternInit struct + * @param base_url an optional valid UTF-8 string + * @param options an optional url_pattern_options struct + * @return url_pattern instance + */ +template +ada_warn_unused tl::expected, errors> +parse_url_pattern(std::variant input, + const std::string_view *base_url = nullptr, + const url_pattern_options *options = nullptr); + +/** + * Computes a href string from a file path. The function assumes + * that the input is a valid ASCII or UTF-8 string. + * @return a href string (starts with file:://) + */ +std::string href_from_file(std::string_view path); +} // namespace ada + +#endif // ADA_IMPLEMENTATION_H +/* end file include/ada/implementation.h */ + +#include +#include +#include +#include + +#if ADA_TESTING +#include +#endif // ADA_TESTING + +namespace ada { + +enum class url_pattern_part_type : uint8_t { + // The part represents a simple fixed text string. + FIXED_TEXT, + // The part represents a matching group with a custom regular expression. + REGEXP, + // The part represents a matching group that matches code points up to the + // next separator code point. This is typically used for a named group like + // ":foo" that does not have a custom regular expression. + SEGMENT_WILDCARD, + // The part represents a matching group that greedily matches all code points. + // This is typically used for the "*" wildcard matching group. + FULL_WILDCARD, +}; + +enum class url_pattern_part_modifier : uint8_t { + // The part does not have a modifier. + none, + // The part has an optional modifier indicated by the U+003F (?) code point. + optional, + // The part has a "zero or more" modifier indicated by the U+002A (*) code + // point. + zero_or_more, + // The part has a "one or more" modifier indicated by the U+002B (+) code + // point. + one_or_more, +}; + +// @see https://urlpattern.spec.whatwg.org/#part +class url_pattern_part { +public: + url_pattern_part(url_pattern_part_type _type, std::string &&_value, + url_pattern_part_modifier _modifier) + : type(_type), value(_value), modifier(_modifier) {} + + url_pattern_part(url_pattern_part_type _type, std::string &&_value, + url_pattern_part_modifier _modifier, std::string &&_name, + std::string &&_prefix, std::string &&_suffix) + : type(_type), value(_value), modifier(_modifier), name(_name), + prefix(_prefix), suffix(_suffix) {} + // A part has an associated type, a string, which must be set upon creation. + url_pattern_part_type type; + // A part has an associated value, a string, which must be set upon creation. + std::string value; + // A part has an associated modifier a string, which must be set upon + // creation. + url_pattern_part_modifier modifier; + // A part has an associated name, a string, initially the empty string. + std::string name{}; + // A part has an associated prefix, a string, initially the empty string. + std::string prefix{}; + // A part has an associated suffix, a string, initially the empty string. + std::string suffix{}; + + inline bool is_regexp() const noexcept; +}; + +// @see https://urlpattern.spec.whatwg.org/#options-header +struct url_pattern_compile_component_options { + url_pattern_compile_component_options() = default; + explicit url_pattern_compile_component_options( + std::optional new_delimiter = std::nullopt, + std::optional new_prefix = std::nullopt) + : delimiter(new_delimiter), prefix(new_prefix) {} + + inline std::string_view get_delimiter() const ada_warn_unused; + inline std::string_view get_prefix() const ada_warn_unused; + + // @see https://urlpattern.spec.whatwg.org/#options-ignore-case + bool ignore_case = false; + + static url_pattern_compile_component_options DEFAULT; + static url_pattern_compile_component_options HOSTNAME; + static url_pattern_compile_component_options PATHNAME; + +private: + // @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point + std::optional delimiter{}; + // @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point + std::optional prefix{}; +}; + +// The default options is an options struct with delimiter code point set to +// the empty string and prefix code point set to the empty string. +inline url_pattern_compile_component_options + url_pattern_compile_component_options::DEFAULT(std::nullopt, std::nullopt); + +// The hostname options is an options struct with delimiter code point set +// "." and prefix code point set to the empty string. +inline url_pattern_compile_component_options + url_pattern_compile_component_options::HOSTNAME('.', std::nullopt); + +// The pathname options is an options struct with delimiter code point set +// "/" and prefix code point set to "/". +inline url_pattern_compile_component_options + url_pattern_compile_component_options::PATHNAME('/', '/'); + +// A struct providing the URLPattern matching results for a single +// URL component. The URLPatternComponentResult is only ever used +// as a member attribute of a URLPatternResult struct. The +// URLPatternComponentResult API is defined as part of the URLPattern +// specification. +struct url_pattern_component_result { + std::string input; + std::unordered_map> groups; + + bool operator==(const url_pattern_component_result &) const; + +#if ADA_TESTING + friend void PrintTo(const url_pattern_component_result &result, + std::ostream *os) { + *os << "input: '" << result.input << "', group: "; + for (const auto &group : result.groups) { + *os << "(" << group.first << ", " << group.second.value_or("undefined") + << ") "; + } + } +#endif // ADA_TESTING +}; + +template +class url_pattern_component { +public: + url_pattern_component() = default; + + // This function explicitly takes a std::string because it is moved. + // To avoid unnecessary copy, move each value while calling the constructor. + url_pattern_component(std::string &&new_pattern, + typename regex_provider::regex_type &&new_regexp, + std::vector &&new_group_name_list, + bool new_has_regexp_groups) + : regexp(std::move(new_regexp)), pattern(std::move(new_pattern)), + group_name_list(new_group_name_list), + has_regexp_groups(new_has_regexp_groups) {} + + // @see https://urlpattern.spec.whatwg.org/#compile-a-component + template + static tl::expected + compile(std::string_view input, F &encoding_callback, + url_pattern_compile_component_options &options); + + // @see https://urlpattern.spec.whatwg.org/#create-a-component-match-result + url_pattern_component_result create_component_match_result( + std::string_view input, + std::vector> &&exec_result); + +#if ADA_TESTING + friend void PrintTo(const url_pattern_component &component, + std::ostream *os) { + *os << "pattern: '" << component.pattern + << "', has_regexp_groups: " << component.has_regexp_groups + << "group_name_list: "; + for (const auto &name : component.group_name_list) { + *os << name << ", "; + } + } +#endif // ADA_TESTING + + typename regex_provider::regex_type regexp{}; + std::string pattern{}; + std::vector group_name_list{}; + bool has_regexp_groups = false; +}; + +using url_pattern_input = std::variant; + +// A struct providing the URLPattern matching results for all +// components of a URL. The URLPatternResult API is defined as +// part of the URLPattern specification. +struct url_pattern_result { + std::vector inputs; + url_pattern_component_result protocol; + url_pattern_component_result username; + url_pattern_component_result password; + url_pattern_component_result hostname; + url_pattern_component_result port; + url_pattern_component_result pathname; + url_pattern_component_result search; + url_pattern_component_result hash; +}; + +struct url_pattern_options { + bool ignore_case = false; + +#if ADA_TESTING + friend void PrintTo(const url_pattern_options &options, std::ostream *os) { + *os << "ignore_case: '" << options.ignore_case; + } +#endif // ADA_TESTING +}; + +// URLPattern is a Web Platform standard API for matching URLs against a +// pattern syntax (think of it as a regular expression for URLs). It is +// defined in https://wicg.github.io/urlpattern. +// More information about the URL Pattern syntax can be found at +// https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API +template class url_pattern { +public: + url_pattern() = default; + + /** + * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec + */ + result> + exec(const url_pattern_input &input, + const std::string_view *base_url = nullptr); + + /** + * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-test + */ + result test(const url_pattern_input &input, + const std::string_view *base_url = nullptr); + + /** + * @see https://urlpattern.spec.whatwg.org/#url-pattern-match + * This function expects a valid UTF-8 string if input is a string. + */ + result> + match(const url_pattern_input &input, + const std::string_view *base_url_string = nullptr); + + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol + [[nodiscard]] std::string_view get_protocol() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-username + [[nodiscard]] std::string_view get_username() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-password + [[nodiscard]] std::string_view get_password() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname + [[nodiscard]] std::string_view get_hostname() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-port + [[nodiscard]] std::string_view get_port() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname + [[nodiscard]] std::string_view get_pathname() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-search + [[nodiscard]] std::string_view get_search() const ada_lifetime_bound; + // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash + [[nodiscard]] std::string_view get_hash() const ada_lifetime_bound; + + // If ignoreCase is true, the JavaScript regular expression created for each + // pattern must use the `vi` flag. Otherwise, they must use the `v` flag. + [[nodiscard]] bool ignore_case() const; + + // @see https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups + [[nodiscard]] bool has_regexp_groups() const; + +#if ADA_TESTING + friend void PrintTo(const url_pattern &c, std::ostream *os) { + *os << "protocol_component: '" << c.get_protocol() << ", "; + *os << "username_component: '" << c.get_username() << ", "; + *os << "password_component: '" << c.get_password() << ", "; + *os << "hostname_component: '" << c.get_hostname() << ", "; + *os << "port_component: '" << c.get_port() << ", "; + *os << "pathname_component: '" << c.get_pathname() << ", "; + *os << "search_component: '" << c.get_search() << ", "; + *os << "hash_component: '" << c.get_hash(); + } +#endif // ADA_TESTING + + template + friend tl::expected, errors> parser::parse_url_pattern_impl( + std::variant input, + const std::string_view *base_url, const url_pattern_options *options); + +private: + url_pattern_component protocol_component{}; + url_pattern_component username_component{}; + url_pattern_component password_component{}; + url_pattern_component hostname_component{}; + url_pattern_component port_component{}; + url_pattern_component pathname_component{}; + url_pattern_component search_component{}; + url_pattern_component hash_component{}; + bool ignore_case_ = false; +}; + +} // namespace ada + +#endif +/* end file include/ada/url_pattern.h */ +/* begin file include/ada/url_pattern_helpers.h */ +/** + * @file url_pattern_helpers.h + * @brief Declaration for the URLPattern helpers. + */ +#ifndef ADA_URL_PATTERN_HELPERS_H +#define ADA_URL_PATTERN_HELPERS_H + +#include +#include +#include + +namespace ada { +enum class errors : uint8_t; +} + +namespace ada::url_pattern_helpers { + +// @see https://urlpattern.spec.whatwg.org/#token +enum class token_type : uint8_t { + INVALID_CHAR, // 0 + OPEN, // 1 + CLOSE, // 2 + REGEXP, // 3 + NAME, // 4 + CHAR, // 5 + ESCAPED_CHAR, // 6 + OTHER_MODIFIER, // 7 + ASTERISK, // 8 + END, // 9 +}; + +std::string to_string(token_type type); + +// @see https://urlpattern.spec.whatwg.org/#tokenize-policy +enum class token_policy { + strict, + lenient, +}; + +// @see https://urlpattern.spec.whatwg.org/#tokens +class token { +public: + token(token_type _type, size_t _index, std::string &&_value) + : type(_type), index(_index), value(std::move(_value)) {} + + // A token has an associated type, a string, initially "invalid-char". + token_type type = token_type::INVALID_CHAR; + + // A token has an associated index, a number, initially 0. It is the position + // of the first code point in the pattern string represented by the token. + size_t index = 0; + + // A token has an associated value, a string, initially the empty string. It + // contains the code points from the pattern string represented by the token. + std::string value{}; +}; + +// @see https://urlpattern.spec.whatwg.org/#pattern-parser +template class url_pattern_parser { +public: + url_pattern_parser(F &encoding_callback_, + std::string_view segment_wildcard_regexp_) + : encoding_callback(encoding_callback_), + segment_wildcard_regexp(segment_wildcard_regexp_) {} + + bool can_continue() const { return index < tokens.size(); } + + // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-token + token *try_consume_token(token_type type); + // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token + token *try_consume_modifier_token(); + // @see + // https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token + token *try_consume_regexp_or_wildcard_token(const token *name_token); + // @see https://urlpattern.spec.whatwg.org/#consume-text + std::string consume_text(); + // @see https://urlpattern.spec.whatwg.org/#consume-a-required-token + bool consume_required_token(token_type type); + // @see + // https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value + std::optional + maybe_add_part_from_the_pending_fixed_value() ada_warn_unused; + // @see https://urlpattern.spec.whatwg.org/#add-a-part + std::optional add_part(std::string_view prefix, token *name_token, + token *regexp_or_wildcard_token, + std::string_view suyffix, + token *modifier_token) ada_warn_unused; + + std::vector tokens{}; + F &encoding_callback; + std::string segment_wildcard_regexp; + std::vector parts{}; + std::string pending_fixed_value{}; + size_t index = 0; + size_t next_numeric_name = 0; +}; + +// @see https://urlpattern.spec.whatwg.org/#tokenizer +class Tokenizer { +public: + explicit Tokenizer(std::string_view new_input, token_policy new_policy) + : input(new_input), policy(new_policy) {} + + // @see https://urlpattern.spec.whatwg.org/#get-the-next-code-point + void get_next_code_point(); + + // @see https://urlpattern.spec.whatwg.org/#seek-and-get-the-next-code-point + void seek_and_get_next_code_point(size_t index); + + // @see https://urlpattern.spec.whatwg.org/#add-a-token + + void add_token(token_type type, size_t next_position, size_t value_position, + size_t value_length); + + // @see https://urlpattern.spec.whatwg.org/#add-a-token-with-default-length + void add_token_with_default_length(token_type type, size_t next_position, + size_t value_position); + + // @see + // https://urlpattern.spec.whatwg.org/#add-a-token-with-default-position-and-length + void add_token_with_defaults(token_type type); + + // @see https://urlpattern.spec.whatwg.org/#process-a-tokenizing-error + std::optional + process_tokenizing_error(size_t next_position, + size_t value_position) ada_warn_unused; + + friend tl::expected, errors> + tokenize(std::string_view input, token_policy policy); + +private: + // has an associated input, a pattern string, initially the empty string. + std::string input; + // has an associated policy, a tokenize policy, initially "strict". + token_policy policy; + // has an associated token list, a token list, initially an empty list. + std::vector token_list{}; + // has an associated index, a number, initially 0. + size_t index = 0; + // has an associated next index, a number, initially 0. + size_t next_index = 0; + // has an associated code point, a Unicode code point, initially null. + char32_t code_point{}; +}; + +// @see https://urlpattern.spec.whatwg.org/#constructor-string-parser +template +struct constructor_string_parser { + explicit constructor_string_parser(std::string_view new_input, + std::vector &&new_token_list) + : input(new_input), token_list(std::move(new_token_list)) {} + + // @see https://urlpattern.spec.whatwg.org/#rewind + void rewind(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-hash-prefix + bool is_hash_prefix(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-search-prefix + bool is_search_prefix(); + + // @see https://urlpattern.spec.whatwg.org/#parse-a-constructor-string + static tl::expected parse(std::string_view input); + + // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser-state + enum class State { + INIT, + PROTOCOL, + AUTHORITY, + USERNAME, + PASSWORD, + HOSTNAME, + PORT, + PATHNAME, + SEARCH, + HASH, + DONE, + }; + + // @see https://urlpattern.spec.whatwg.org/#change-state + void change_state(State state, size_t skip); + + // @see https://urlpattern.spec.whatwg.org/#is-a-group-open + bool is_group_open() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-group-close + bool is_group_close() const; + + // @see https://urlpattern.spec.whatwg.org/#is-a-protocol-suffix + bool is_protocol_suffix(); + + // @see + // https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag + std::optional compute_protocol_matches_special_scheme_flag(); + + // @see https://urlpattern.spec.whatwg.org/#next-is-authority-slashes + bool next_is_authority_slashes(); + + // @see https://urlpattern.spec.whatwg.org/#is-an-identity-terminator + bool is_an_identity_terminator(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-pathname-start + bool is_pathname_start(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-password-prefix + bool is_password_prefix(); + + // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-open + bool is_an_ipv6_open(); + + // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-close + bool is_an_ipv6_close(); + + // @see https://urlpattern.spec.whatwg.org/#is-a-port-prefix + bool is_port_prefix(); + +private: + // @see https://urlpattern.spec.whatwg.org/#is-a-non-special-pattern-char + bool is_non_special_pattern_char(size_t index, std::string_view value); + + // @see https://urlpattern.spec.whatwg.org/#get-a-safe-token + const token *get_safe_token(size_t index); + + // @see https://urlpattern.spec.whatwg.org/#make-a-component-string + std::string make_component_string(); + // has an associated input, a string, which must be set upon creation. + std::string input; + // has an associated token list, a token list, which must be set upon + // creation. + std::vector token_list; + // has an associated result, a URLPatternInit, initially set to a new + // URLPatternInit. + url_pattern_init result{}; + // has an associated component start, a number, initially set to 0. + size_t component_start = 0; + // has an associated token index, a number, initially set to 0. + size_t token_index = 0; + // has an associated token increment, a number, initially set to 1. + size_t token_increment = 1; + // has an associated group depth, a number, initially set to 0. + size_t group_depth = 0; + // has an associated hostname IPv6 bracket depth, a number, initially set to + // 0. + size_t hostname_ipv6_bracket_depth = 0; + // has an associated protocol matches a special scheme flag, a boolean, + // initially set to false. + bool protocol_matches_a_special_scheme_flag = false; + // has an associated state, a string, initially set to "init". + State state = State::INIT; +}; + +// @see https://urlpattern.spec.whatwg.org/#canonicalize-a-protocol +tl::expected canonicalize_protocol(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-username +tl::expected canonicalize_username(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-password +tl::expected canonicalize_password(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-password +tl::expected canonicalize_hostname(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-an-ipv6-hostname +tl::expected +canonicalize_ipv6_hostname(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-port +tl::expected canonicalize_port(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-port +tl::expected +canonicalize_port_with_protocol(std::string_view input, + std::string_view protocol); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-pathname +tl::expected canonicalize_pathname(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-an-opaque-pathname +tl::expected +canonicalize_opaque_pathname(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-search +tl::expected canonicalize_search(std::string_view input); + +// @see https://wicg.github.io/urlpattern/#canonicalize-a-hash +tl::expected canonicalize_hash(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#tokenize +tl::expected, errors> tokenize(std::string_view input, + token_policy policy); + +// @see https://urlpattern.spec.whatwg.org/#process-a-base-url-string +std::string process_base_url_string(std::string_view input, + std::string_view type); + +// @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string +std::string escape_pattern_string(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#escape-a-regexp-string +std::string escape_regexp_string(std::string_view input); + +// @see https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname +constexpr bool is_absolute_pathname(std::string_view input, + std::string_view type) noexcept; + +// @see https://urlpattern.spec.whatwg.org/#parse-a-pattern-string +template +tl::expected, errors> +parse_pattern_string(std::string_view input, + url_pattern_compile_component_options &options, + F &encoding_callback); + +// @see https://urlpattern.spec.whatwg.org/#generate-a-pattern-string +std::string +generate_pattern_string(std::vector &part_list, + url_pattern_compile_component_options &options); + +// @see +// https://urlpattern.spec.whatwg.org/#generate-a-regular-expression-and-name-list +std::tuple> +generate_regular_expression_and_name_list( + const std::vector &part_list, + url_pattern_compile_component_options options); + +// @see https://urlpattern.spec.whatwg.org/#hostname-pattern-is-an-ipv6-address +bool is_ipv6_address(std::string_view input) noexcept; + +// @see +// https://urlpattern.spec.whatwg.org/#protocol-component-matches-a-special-scheme +template +bool protocol_component_matches_special_scheme( + ada::url_pattern_component &input); + +// @see https://urlpattern.spec.whatwg.org/#convert-a-modifier-to-a-string +std::string convert_modifier_to_string(url_pattern_part_modifier modifier); + +// @see https://urlpattern.spec.whatwg.org/#generate-a-segment-wildcard-regexp +std::string +generate_segment_wildcard_regexp(url_pattern_compile_component_options options); + +} // namespace ada::url_pattern_helpers + +#endif +/* end file include/ada/url_pattern_helpers.h */ + +#include +#include + +namespace ada::parser { +template +tl::expected, errors> +parse_url_pattern_impl(std::variant input, + const std::string_view *base_url, + const url_pattern_options *options) { + // Let init be null. + url_pattern_init init; + + // If input is a scalar value string then: + if (std::holds_alternative(input)) { + // Set init to the result of running parse a constructor string given input. + auto parse_result = + url_pattern_helpers::constructor_string_parser::parse( + std::get(input)); + if (!parse_result) { + ada_log("constructor_string_parser::parse failed"); + return tl::unexpected(parse_result.error()); + } + init = std::move(*parse_result); + // If baseURL is null and init["protocol"] does not exist, then throw a + // TypeError. + if (!base_url && !init.protocol) { + ada_log("base url is null and protocol is not set"); + return tl::unexpected(errors::type_error); + } + + // If baseURL is not null, set init["baseURL"] to baseURL. + if (base_url) { + init.base_url = std::string(*base_url); + } + } else { + // Assert: input is a URLPatternInit. + ADA_ASSERT_TRUE(std::holds_alternative(input)); + // If baseURL is not null, then throw a TypeError. + if (base_url) { + ada_log("base url is not null"); + return tl::unexpected(errors::type_error); + } + // Optimization: Avoid copy by moving the input value. + // Set init to input. + init = std::move(std::get(input)); + } + + // Let processedInit be the result of process a URLPatternInit given init, + // "pattern", null, null, null, null, null, null, null, and null. + // TODO: Make "pattern" an enum to avoid creating a string everytime. + auto processed_init = url_pattern_init::process(init, "pattern"); + if (!processed_init) { + ada_log("url_pattern_init::process failed for init and 'pattern'"); + return tl::unexpected(processed_init.error()); + } + + // For each componentName of « "protocol", "username", "password", "hostname", + // "port", "pathname", "search", "hash" If processedInit[componentName] does + // not exist, then set processedInit[componentName] to "*". + ADA_ASSERT_TRUE(processed_init.has_value()); + if (!processed_init->protocol) + processed_init->protocol = "*"; + if (!processed_init->username) + processed_init->username = "*"; + if (!processed_init->password) + processed_init->password = "*"; + if (!processed_init->hostname) + processed_init->hostname = "*"; + if (!processed_init->port) + processed_init->port = "*"; + if (!processed_init->pathname) + processed_init->pathname = "*"; + if (!processed_init->search) + processed_init->search = "*"; + if (!processed_init->hash) + processed_init->hash = "*"; + + ada_log("-- processed_init->protocol: ", processed_init->protocol.value()); + ada_log("-- processed_init->username: ", processed_init->username.value()); + ada_log("-- processed_init->password: ", processed_init->password.value()); + ada_log("-- processed_init->hostname: ", processed_init->hostname.value()); + ada_log("-- processed_init->port: ", processed_init->port.value()); + ada_log("-- processed_init->pathname: ", processed_init->pathname.value()); + ada_log("-- processed_init->search: ", processed_init->search.value()); + ada_log("-- processed_init->hash: ", processed_init->hash.value()); + + // If processedInit["protocol"] is a special scheme and processedInit["port"] + // is a string which represents its corresponding default port in radix-10 + // using ASCII digits then set processedInit["port"] to the empty string. + // TODO: Optimization opportunity. + if (scheme::is_special(*processed_init->protocol)) { + std::string_view port = processed_init->port.value(); + helpers::trim_c0_whitespace(port); + if (std::to_string(scheme::get_special_port(*processed_init->protocol)) == + port) { + processed_init->port->clear(); + } + } + + // Let urlPattern be a new URL pattern. + url_pattern url_pattern_{}; + + // Set urlPattern’s protocol component to the result of compiling a component + // given processedInit["protocol"], canonicalize a protocol, and default + // options. + auto protocol_component = url_pattern_component::compile( + processed_init->protocol.value(), + url_pattern_helpers::canonicalize_protocol, + url_pattern_compile_component_options::DEFAULT); + if (!protocol_component) { + ada_log("url_pattern_component::compile failed for protocol ", + processed_init->protocol.value()); + return tl::unexpected(protocol_component.error()); + } + url_pattern_.protocol_component = std::move(*protocol_component); + + // Set urlPattern’s username component to the result of compiling a component + // given processedInit["username"], canonicalize a username, and default + // options. + auto username_component = url_pattern_component::compile( + processed_init->username.value(), + url_pattern_helpers::canonicalize_username, + url_pattern_compile_component_options::DEFAULT); + if (!username_component) { + ada_log("url_pattern_component::compile failed for username ", + processed_init->username.value()); + return tl::unexpected(username_component.error()); + } + url_pattern_.username_component = std::move(*username_component); + + // Set urlPattern’s password component to the result of compiling a component + // given processedInit["password"], canonicalize a password, and default + // options. + auto password_component = url_pattern_component::compile( + processed_init->password.value(), + url_pattern_helpers::canonicalize_password, + url_pattern_compile_component_options::DEFAULT); + if (!password_component) { + ada_log("url_pattern_component::compile failed for password ", + processed_init->password.value()); + return tl::unexpected(password_component.error()); + } + url_pattern_.password_component = std::move(*password_component); + + // TODO: Optimization opportunity. The following if statement can be + // simplified. + // If the result running hostname pattern is an IPv6 address given + // processedInit["hostname"] is true, then set urlPattern’s hostname component + // to the result of compiling a component given processedInit["hostname"], + // canonicalize an IPv6 hostname, and hostname options. + if (url_pattern_helpers::is_ipv6_address(processed_init->hostname.value())) { + ada_log("processed_init->hostname is ipv6 address"); + // then set urlPattern’s hostname component to the result of compiling a + // component given processedInit["hostname"], canonicalize an IPv6 hostname, + // and hostname options. + auto hostname_component = url_pattern_component::compile( + processed_init->hostname.value(), + url_pattern_helpers::canonicalize_ipv6_hostname, + url_pattern_compile_component_options::DEFAULT); + if (!hostname_component) { + ada_log("url_pattern_component::compile failed for ipv6 hostname ", + processed_init->hostname.value()); + return tl::unexpected(hostname_component.error()); + } + url_pattern_.hostname_component = std::move(*hostname_component); + } else { + // Otherwise, set urlPattern’s hostname component to the result of compiling + // a component given processedInit["hostname"], canonicalize a hostname, and + // hostname options. + auto hostname_component = url_pattern_component::compile( + processed_init->hostname.value(), + url_pattern_helpers::canonicalize_hostname, + url_pattern_compile_component_options::HOSTNAME); + if (!hostname_component) { + ada_log("url_pattern_component::compile failed for hostname ", + processed_init->hostname.value()); + return tl::unexpected(hostname_component.error()); + } + url_pattern_.hostname_component = std::move(*hostname_component); + } + + // Set urlPattern’s port component to the result of compiling a component + // given processedInit["port"], canonicalize a port, and default options. + auto port_component = url_pattern_component::compile( + processed_init->port.value(), url_pattern_helpers::canonicalize_port, + url_pattern_compile_component_options::DEFAULT); + if (!port_component) { + ada_log("url_pattern_component::compile failed for port ", + processed_init->port.value()); + return tl::unexpected(port_component.error()); + } + url_pattern_.port_component = std::move(*port_component); + + // Let compileOptions be a copy of the default options with the ignore case + // property set to options["ignoreCase"]. + auto compile_options = url_pattern_compile_component_options::DEFAULT; + if (options) { + compile_options.ignore_case = options->ignore_case; + } + + // TODO: Optimization opportunity: Simplify this if statement. + // If the result of running protocol component matches a special scheme given + // urlPattern’s protocol component is true, then: + if (url_pattern_helpers::protocol_component_matches_special_scheme< + regex_provider>(url_pattern_.protocol_component)) { + // Let pathCompileOptions be copy of the pathname options with the ignore + // case property set to options["ignoreCase"]. + auto path_compile_options = url_pattern_compile_component_options::PATHNAME; + if (options) { + path_compile_options.ignore_case = options->ignore_case; + } + + // Set urlPattern’s pathname component to the result of compiling a + // component given processedInit["pathname"], canonicalize a pathname, and + // pathCompileOptions. + auto pathname_component = url_pattern_component::compile( + processed_init->pathname.value(), + url_pattern_helpers::canonicalize_pathname, path_compile_options); + if (!pathname_component) { + ada_log("url_pattern_component::compile failed for pathname ", + processed_init->pathname.value()); + return tl::unexpected(pathname_component.error()); + } + url_pattern_.pathname_component = std::move(*pathname_component); + } else { + // Otherwise set urlPattern’s pathname component to the result of compiling + // a component given processedInit["pathname"], canonicalize an opaque + // pathname, and compileOptions. + auto pathname_component = url_pattern_component::compile( + processed_init->pathname.value(), + url_pattern_helpers::canonicalize_opaque_pathname, compile_options); + if (!pathname_component) { + ada_log("url_pattern_component::compile failed for opaque pathname ", + processed_init->pathname.value()); + return tl::unexpected(pathname_component.error()); + } + url_pattern_.pathname_component = std::move(*pathname_component); + } + + // Set urlPattern’s search component to the result of compiling a component + // given processedInit["search"], canonicalize a search, and compileOptions. + auto search_component = url_pattern_component::compile( + processed_init->search.value(), url_pattern_helpers::canonicalize_search, + compile_options); + if (!search_component) { + ada_log("url_pattern_component::compile failed for search ", + processed_init->search.value()); + return tl::unexpected(search_component.error()); + } + url_pattern_.search_component = std::move(*search_component); + + // Set urlPattern’s hash component to the result of compiling a component + // given processedInit["hash"], canonicalize a hash, and compileOptions. + auto hash_component = url_pattern_component::compile( + processed_init->hash.value(), url_pattern_helpers::canonicalize_hash, + compile_options); + if (!hash_component) { + ada_log("url_pattern_component::compile failed for hash ", + processed_init->hash.value()); + return tl::unexpected(hash_component.error()); + } + url_pattern_.hash_component = std::move(*hash_component); + + // Return urlPattern. + return url_pattern_; +} + +} // namespace ada::parser + +#endif // ADA_PARSER_INL_H +/* end file include/ada/parser-inl.h */ +/* begin file include/ada/scheme-inl.h */ +/** + * @file scheme-inl.h + * @brief Definitions for the URL scheme. + */ +#ifndef ADA_SCHEME_INL_H +#define ADA_SCHEME_INL_H + +namespace ada::scheme { + +/** + * @namespace ada::scheme::details + * @brief Includes the definitions for scheme specific entities + */ +namespace details { +// for use with is_special and get_special_port +// Spaces, if present, are removed from URL. +constexpr std::string_view is_special_list[] = {"http", " ", "https", "ws", + "ftp", "wss", "file", " "}; +// for use with get_special_port +constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0}; +} // namespace details + +/**** + * @private + * In is_special, get_scheme_type, and get_special_port, we + * use a standard hashing technique to find the index of the scheme in + * the is_special_list. The hashing technique is based on the size of + * the scheme and the first character of the scheme. It ensures that we + * do at most one string comparison per call. If the protocol is + * predictible (e.g., it is always "http"), we can get a better average + * performance by using a simpler approach where we loop and compare + * scheme with all possible protocols starting with the most likely + * protocol. Doing multiple comparisons may have a poor worst case + * performance, however. In this instance, we choose a potentially + * slightly lower best-case performance for a better worst-case + * performance. We can revisit this choice at any time. + * + * Reference: + * Schmidt, Douglas C. "Gperf: A perfect hash function generator." + * More C++ gems 17 (2000). + * + * Reference: https://en.wikipedia.org/wiki/Perfect_hash_function + * + * Reference: https://github.com/ada-url/ada/issues/617 + ****/ + +ada_really_inline constexpr bool is_special(std::string_view scheme) { + if (scheme.empty()) { + return false; + } + int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7; + const std::string_view target = details::is_special_list[hash_value]; + return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1)); +} +constexpr uint16_t get_special_port(std::string_view scheme) noexcept { + if (scheme.empty()) { + return 0; + } + int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7; + const std::string_view target = details::is_special_list[hash_value]; + if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) { + return details::special_ports[hash_value]; + } else { + return 0; + } +} +constexpr uint16_t get_special_port(ada::scheme::type type) noexcept { + return details::special_ports[int(type)]; +} +constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept { + if (scheme.empty()) { + return ada::scheme::NOT_SPECIAL; + } + int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7; + const std::string_view target = details::is_special_list[hash_value]; + if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) { + return ada::scheme::type(hash_value); + } else { + return ada::scheme::NOT_SPECIAL; + } +} + +} // namespace ada::scheme + +#endif // ADA_SCHEME_INL_H +/* end file include/ada/scheme-inl.h */ +/* begin file include/ada/serializers.h */ +/** + * @file serializers.h + * @brief Definitions for the URL serializers. + */ +#ifndef ADA_SERIALIZERS_H +#define ADA_SERIALIZERS_H + +#include +#include + +/** + * @namespace ada::serializers + * @brief Includes the definitions for URL serializers + */ +namespace ada::serializers { + +/** + * Finds and returns the longest sequence of 0 values in a ipv6 input. + */ +void find_longest_sequence_of_ipv6_pieces( + const std::array &address, size_t &compress, + size_t &compress_length) noexcept; + +/** + * Serializes an ipv6 address. + * @details An IPv6 address is a 128-bit unsigned integer that identifies a + * network address. + * @see https://url.spec.whatwg.org/#concept-ipv6-serializer + */ +std::string ipv6(const std::array &address) noexcept; + +/** + * Serializes an ipv4 address. + * @details An IPv4 address is a 32-bit unsigned integer that identifies a + * network address. + * @see https://url.spec.whatwg.org/#concept-ipv4-serializer + */ +std::string ipv4(uint64_t address) noexcept; + +} // namespace ada::serializers + +#endif // ADA_SERIALIZERS_H +/* end file include/ada/serializers.h */ +/* begin file include/ada/state.h */ +/** + * @file state.h + * @brief Definitions for the states of the URL state machine. + */ +#ifndef ADA_STATE_H +#define ADA_STATE_H + +#include + +namespace ada { + +/** + * @see https://url.spec.whatwg.org/#url-parsing + */ +enum class state { + /** + * @see https://url.spec.whatwg.org/#authority-state + */ + AUTHORITY, + + /** + * @see https://url.spec.whatwg.org/#scheme-start-state + */ + SCHEME_START, + + /** + * @see https://url.spec.whatwg.org/#scheme-state + */ + SCHEME, + + /** + * @see https://url.spec.whatwg.org/#host-state + */ + HOST, + + /** + * @see https://url.spec.whatwg.org/#no-scheme-state + */ + NO_SCHEME, + + /** + * @see https://url.spec.whatwg.org/#fragment-state + */ + FRAGMENT, + + /** + * @see https://url.spec.whatwg.org/#relative-state + */ + RELATIVE_SCHEME, + + /** + * @see https://url.spec.whatwg.org/#relative-slash-state + */ + RELATIVE_SLASH, + + /** + * @see https://url.spec.whatwg.org/#file-state + */ + FILE, + + /** + * @see https://url.spec.whatwg.org/#file-host-state + */ + FILE_HOST, + + /** + * @see https://url.spec.whatwg.org/#file-slash-state + */ + FILE_SLASH, + + /** + * @see https://url.spec.whatwg.org/#path-or-authority-state + */ + PATH_OR_AUTHORITY, + + /** + * @see https://url.spec.whatwg.org/#special-authority-ignore-slashes-state + */ + SPECIAL_AUTHORITY_IGNORE_SLASHES, + + /** + * @see https://url.spec.whatwg.org/#special-authority-slashes-state + */ + SPECIAL_AUTHORITY_SLASHES, + + /** + * @see https://url.spec.whatwg.org/#special-relative-or-authority-state + */ + SPECIAL_RELATIVE_OR_AUTHORITY, + + /** + * @see https://url.spec.whatwg.org/#query-state + */ + QUERY, + + /** + * @see https://url.spec.whatwg.org/#path-state + */ + PATH, + + /** + * @see https://url.spec.whatwg.org/#path-start-state + */ + PATH_START, + + /** + * @see https://url.spec.whatwg.org/#cannot-be-a-base-url-path-state + */ + OPAQUE_PATH, + + /** + * @see https://url.spec.whatwg.org/#port-state + */ + PORT, +}; + +/** + * Stringify a URL state machine state. + */ +ada_warn_unused std::string to_string(ada::state s); + +} // namespace ada + +#endif // ADA_STATE_H +/* end file include/ada/state.h */ +/* begin file include/ada/unicode.h */ +/** + * @file unicode.h + * @brief Definitions for all unicode specific functions. + */ +#ifndef ADA_UNICODE_H +#define ADA_UNICODE_H + +#include +#include + +/** + * Unicode operations. These functions are not part of our public API and may + * change at any time. + * + * @private + * @namespace ada::unicode + * @brief Includes the definitions for unicode operations + */ +namespace ada::unicode { + +/** + * @private + * We receive a UTF-8 string representing a domain name. + * If the string is percent encoded, we apply percent decoding. + * + * Given a domain, we need to identify its labels. + * They are separated by label-separators: + * + * U+002E (.) FULL STOP + * U+FF0E FULLWIDTH FULL STOP + * U+3002 IDEOGRAPHIC FULL STOP + * U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP + * + * They are all mapped to U+002E. + * + * We process each label into a string that should not exceed 63 octets. + * If the string is already punycode (starts with "xn--"), then we must + * scan it to look for unallowed code points. + * Otherwise, if the string is not pure ASCII, we need to transcode it + * to punycode by following RFC 3454 which requires us to + * - Map characters (see section 3), + * - Normalize (see section 4), + * - Reject forbidden characters, + * - Check for right-to-left characters and if so, check all requirements (see + * section 6), + * - Optionally reject based on unassigned code points (section 7). + * + * The Unicode standard provides a table of code points with a mapping, a list + * of forbidden code points and so forth. This table is subject to change and + * will vary based on the implementation. For Unicode 15, the table is at + * https://www.unicode.org/Public/idna/15.0.0/IdnaMappingTable.txt + * If you use ICU, they parse this table and map it to code using a Python + * script. + * + * The resulting strings should not exceed 255 octets according to RFC 1035 + * section 2.3.4. ICU checks for label size and domain size, but these errors + * are ignored. + * + * @see https://url.spec.whatwg.org/#concept-domain-to-ascii + * + */ +bool to_ascii(std::optional &out, std::string_view plain, + size_t first_percent); + +/** + * @private + * Checks if the input has tab or newline characters. + * + * @attention The has_tabs_or_newline function is a bottleneck and it is simple + * enough that compilers like GCC can 'autovectorize it'. + */ +ada_really_inline bool +has_tabs_or_newline(std::string_view user_input) noexcept; + +/** + * @private + * Checks if the input is a forbidden host code point. + * @see https://url.spec.whatwg.org/#forbidden-host-code-point + */ +ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept; + +/** + * @private + * Checks if the input contains a forbidden domain code point. + * @see https://url.spec.whatwg.org/#forbidden-domain-code-point + */ +ada_really_inline constexpr bool +contains_forbidden_domain_code_point(const char *input, size_t length) noexcept; + +/** + * @private + * Checks if the input contains a forbidden domain code point in which case + * the first bit is set to 1. If the input contains an upper case ASCII letter, + * then the second bit is set to 1. + * @see https://url.spec.whatwg.org/#forbidden-domain-code-point + */ +ada_really_inline constexpr uint8_t +contains_forbidden_domain_code_point_or_upper(const char *input, + size_t length) noexcept; + +/** + * @private + * Checks if the input is a forbidden domain code point. + * @see https://url.spec.whatwg.org/#forbidden-domain-code-point + */ +ada_really_inline constexpr bool +is_forbidden_domain_code_point(char c) noexcept; + +/** + * @private + * Checks if the input is alphanumeric, '+', '-' or '.' + */ +ada_really_inline constexpr bool is_alnum_plus(char c) noexcept; + +/** + * @private + * @details An ASCII hex digit is an ASCII upper hex digit or ASCII lower hex + * digit. An ASCII upper hex digit is an ASCII digit or a code point in the + * range U+0041 (A) to U+0046 (F), inclusive. An ASCII lower hex digit is an + * ASCII digit or a code point in the range U+0061 (a) to U+0066 (f), inclusive. + */ +ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept; + +/** + * @private + * An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9), + * inclusive. + */ +ada_really_inline constexpr bool is_ascii_digit(char c) noexcept; + +/** + * @private + * @details If a char is between U+0000 and U+007F inclusive, then it's an ASCII + * character. + */ +ada_really_inline constexpr bool is_ascii(char32_t c) noexcept; + +/** + * @private + * Checks if the input is a C0 control or space character. + * + * @details A C0 control or space is a C0 control or U+0020 SPACE. + * A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION + * SEPARATOR ONE, inclusive. + */ +ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept; + +/** + * @private + * Checks if the input is a ASCII tab or newline character. + * + * @details An ASCII tab or newline is U+0009 TAB, U+000A LF, or U+000D CR. + */ +ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept; + +/** + * @private + * @details A double-dot path segment must be ".." or an ASCII case-insensitive + * match for ".%2e", "%2e.", or "%2e%2e". + */ +ada_really_inline constexpr bool +is_double_dot_path_segment(std::string_view input) noexcept; + +/** + * @private + * @details A single-dot path segment must be "." or an ASCII case-insensitive + * match for "%2e". + */ +ada_really_inline constexpr bool +is_single_dot_path_segment(std::string_view input) noexcept; + +/** + * @private + * @details ipv4 character might contain 0-9 or a-f character ranges. + */ +ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept; + +/** + * @private + * @details Convert hex to binary. Caller is responsible to ensure that + * the parameter is an hexadecimal digit (0-9, A-F, a-f). + */ +ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept; + +/** + * @private + * first_percent should be = input.find('%') + * + * @todo It would be faster as noexcept maybe, but it could be unsafe since. + * @author Node.js + * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L245 + * @see https://encoding.spec.whatwg.org/#utf-8-decode-without-bom + */ +std::string percent_decode(std::string_view input, size_t first_percent); + +/** + * @private + * Returns a percent-encoding string whether percent encoding was needed or not. + * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226 + */ +std::string percent_encode(std::string_view input, + const uint8_t character_set[]); +/** + * @private + * Returns a percent-encoded string version of input, while starting the percent + * encoding at the provided index. + * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226 + */ +std::string percent_encode(std::string_view input, + const uint8_t character_set[], size_t index); +/** + * @private + * Returns true if percent encoding was needed, in which case, we store + * the percent-encoded content in 'out'. If the boolean 'append' is set to + * true, the content is appended to 'out'. + * If percent encoding is not needed, out is left unchanged. + * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226 + */ +template +bool percent_encode(std::string_view input, const uint8_t character_set[], + std::string &out); +/** + * @private + * Returns the index at which percent encoding should start, or (equivalently), + * the length of the prefix that does not require percent encoding. + */ +ada_really_inline size_t percent_encode_index(std::string_view input, + const uint8_t character_set[]); +/** + * @private + * Lowers the string in-place, assuming that the content is ASCII. + * Return true if the content was ASCII. + */ +constexpr bool to_lower_ascii(char *input, size_t length) noexcept; +} // namespace ada::unicode + +#endif // ADA_UNICODE_H +/* end file include/ada/unicode.h */ +/* begin file include/ada/url_base-inl.h */ +/** + * @file url_base-inl.h + * @brief Inline functions for url base + */ +#ifndef ADA_URL_BASE_INL_H +#define ADA_URL_BASE_INL_H + +#include +#if ADA_REGULAR_VISUAL_STUDIO +#include +#endif // ADA_REGULAR_VISUAL_STUDIO + +namespace ada { + +[[nodiscard]] ada_really_inline constexpr bool +url_base::is_special() const noexcept { + return type != ada::scheme::NOT_SPECIAL; +} + +[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept { + return ada::scheme::get_special_port(type); +} + +[[nodiscard]] ada_really_inline uint16_t +url_base::scheme_default_port() const noexcept { + return scheme::get_special_port(type); +} + +} // namespace ada + +#endif // ADA_URL_BASE_INL_H +/* end file include/ada/url_base-inl.h */ +/* begin file include/ada/url-inl.h */ +/** + * @file url-inl.h + * @brief Definitions for the URL + */ +#ifndef ADA_URL_INL_H +#define ADA_URL_INL_H + +#include +#include +#include +#if ADA_REGULAR_VISUAL_STUDIO +#include +#endif // ADA_REGULAR_VISUAL_STUDIO + +namespace ada { +[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept { + return !username.empty() || !password.empty(); +} +[[nodiscard]] ada_really_inline bool url::has_port() const noexcept { + return port.has_value(); +} +[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const { + return !host.has_value() || host.value().empty() || + type == ada::scheme::type::FILE; +} +[[nodiscard]] inline bool url::has_empty_hostname() const noexcept { + if (!host.has_value()) { + return false; + } + return host.value().empty(); +} +[[nodiscard]] inline bool url::has_hostname() const noexcept { + return host.has_value(); +} +inline std::ostream &operator<<(std::ostream &out, const ada::url &u) { + return out << u.to_string(); +} + +[[nodiscard]] size_t url::get_pathname_length() const noexcept { + return path.size(); +} + +[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept { + return path; +} + +[[nodiscard]] ada_really_inline ada::url_components +url::get_components() const noexcept { + url_components out{}; + + // protocol ends with ':'. for example: "https:" + out.protocol_end = uint32_t(get_protocol().size()); + + // Trailing index is always the next character of the current one. + size_t running_index = out.protocol_end; + + if (host.has_value()) { + // 2 characters for "//" and 1 character for starting index + out.host_start = out.protocol_end + 2; + + if (has_credentials()) { + out.username_end = uint32_t(out.host_start + username.size()); + + out.host_start += uint32_t(username.size()); + + if (!password.empty()) { + out.host_start += uint32_t(password.size() + 1); + } + + out.host_end = uint32_t(out.host_start + host.value().size()); + } else { + out.username_end = out.host_start; + + // Host does not start with "@" if it does not include credentials. + out.host_end = uint32_t(out.host_start + host.value().size()) - 1; + } + + running_index = out.host_end + 1; + } else { + // Update host start and end date to the same index, since it does not + // exist. + out.host_start = out.protocol_end; + out.host_end = out.host_start; + + if (!has_opaque_path && path.starts_with("//")) { + // If url's host is null, url does not have an opaque path, url's path's + // size is greater than 1, and url's path[0] is the empty string, then + // append U+002F (/) followed by U+002E (.) to output. + running_index = out.protocol_end + 2; + } else { + running_index = out.protocol_end; + } + } + + if (port.has_value()) { + out.port = *port; + running_index += helpers::fast_digit_count(*port) + 1; // Port omits ':' + } + + out.pathname_start = uint32_t(running_index); + + running_index += path.size(); + + if (query.has_value()) { + out.search_start = uint32_t(running_index); + running_index += get_search().size(); + if (get_search().empty()) { + running_index++; + } + } + + if (hash.has_value()) { + out.hash_start = uint32_t(running_index); + } + + return out; +} + +inline void url::update_base_hostname(std::string_view input) { host = input; } + +inline void url::update_unencoded_base_hash(std::string_view input) { + // We do the percent encoding + hash = unicode::percent_encode(input, + ada::character_sets::FRAGMENT_PERCENT_ENCODE); +} + +inline void url::update_base_search(std::string_view input, + const uint8_t query_percent_encode_set[]) { + query = ada::unicode::percent_encode(input, query_percent_encode_set); +} + +inline void url::update_base_search(std::optional &&input) { + query = std::move(input); +} + +inline void url::update_base_pathname(const std::string_view input) { + path = input; +} + +inline void url::update_base_username(const std::string_view input) { + username = input; +} + +inline void url::update_base_password(const std::string_view input) { + password = input; +} + +inline void url::update_base_port(std::optional input) { + port = input; +} + +constexpr void url::clear_pathname() { path.clear(); } + +constexpr void url::clear_search() { query = std::nullopt; } + +[[nodiscard]] constexpr bool url::has_hash() const noexcept { + return hash.has_value(); +} + +[[nodiscard]] constexpr bool url::has_search() const noexcept { + return query.has_value(); +} + +constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; } + +inline void url::set_scheme(std::string &&new_scheme) noexcept { + type = ada::scheme::get_scheme_type(new_scheme); + // We only move the 'scheme' if it is non-special. + if (!is_special()) { + non_special_scheme = std::move(new_scheme); + } +} + +constexpr void url::copy_scheme(ada::url &&u) noexcept { + non_special_scheme = u.non_special_scheme; + type = u.type; +} + +constexpr void url::copy_scheme(const ada::url &u) { + non_special_scheme = u.non_special_scheme; + type = u.type; +} + +[[nodiscard]] ada_really_inline std::string url::get_href() const noexcept { + std::string output = get_protocol(); + + if (host.has_value()) { + output += "//"; + if (has_credentials()) { + output += username; + if (!password.empty()) { + output += ":" + get_password(); + } + output += "@"; + } + output += host.value(); + if (port.has_value()) { + output += ":" + get_port(); + } + } else if (!has_opaque_path && path.starts_with("//")) { + // If url's host is null, url does not have an opaque path, url's path's + // size is greater than 1, and url's path[0] is the empty string, then + // append U+002F (/) followed by U+002E (.) to output. + output += "/."; + } + output += path; + if (query.has_value()) { + output += "?" + query.value(); + } + if (hash.has_value()) { + output += "#" + hash.value(); + } + return output; +} + +ada_really_inline size_t url::parse_port(std::string_view view, + bool check_trailing_content) noexcept { + ada_log("parse_port('", view, "') ", view.size()); + if (!view.empty() && view[0] == '-') { + ada_log("parse_port: view[0] == '0' && view.size() > 1"); + is_valid = false; + return 0; + } + uint16_t parsed_port{}; + auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port); + if (r.ec == std::errc::result_out_of_range) { + ada_log("parse_port: r.ec == std::errc::result_out_of_range"); + is_valid = false; + return 0; + } + ada_log("parse_port: ", parsed_port); + const auto consumed = size_t(r.ptr - view.data()); + ada_log("parse_port: consumed ", consumed); + if (check_trailing_content) { + is_valid &= + (consumed == view.size() || view[consumed] == '/' || + view[consumed] == '?' || (is_special() && view[consumed] == '\\')); + } + ada_log("parse_port: is_valid = ", is_valid); + if (is_valid) { + // scheme_default_port can return 0, and we should allow 0 as a base port. + auto default_port = scheme_default_port(); + bool is_port_valid = (default_port == 0 && parsed_port == 0) || + (default_port != parsed_port); + port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port) + : std::nullopt; + } + return consumed; +} + +} // namespace ada + +#endif // ADA_URL_H +/* end file include/ada/url-inl.h */ +/* begin file include/ada/url_components-inl.h */ +/** + * @file url_components.h + * @brief Declaration for the URL Components + */ +#ifndef ADA_URL_COMPONENTS_INL_H +#define ADA_URL_COMPONENTS_INL_H + +namespace ada { + +[[nodiscard]] constexpr bool +url_components::check_offset_consistency() const noexcept { + /** + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + */ + // These conditions can be made more strict. + if (protocol_end == url_components::omitted) { + return false; + } + uint32_t index = protocol_end; + + if (username_end == url_components::omitted) { + return false; + } + if (username_end < index) { + return false; + } + index = username_end; + + if (host_start == url_components::omitted) { + return false; + } + if (host_start < index) { + return false; + } + index = host_start; + + if (port != url_components::omitted) { + if (port > 0xffff) { + return false; + } + uint32_t port_length = helpers::fast_digit_count(port) + 1; + if (index + port_length < index) { + return false; + } + index += port_length; + } + + if (pathname_start == url_components::omitted) { + return false; + } + if (pathname_start < index) { + return false; + } + index = pathname_start; + + if (search_start != url_components::omitted) { + if (search_start < index) { + return false; + } + index = search_start; + } + + if (hash_start != url_components::omitted) { + if (hash_start < index) { + return false; + } + } + + return true; +} + +} // namespace ada +#endif +/* end file include/ada/url_components-inl.h */ +/* begin file include/ada/url_aggregator.h */ +/** + * @file url_aggregator.h + * @brief Declaration for the basic URL definitions + */ +#ifndef ADA_URL_AGGREGATOR_H +#define ADA_URL_AGGREGATOR_H + +#include +#include +#include + +namespace ada { + +namespace parser {} + +/** + * @brief Lightweight URL struct. + * + * @details The url_aggregator class aims to minimize temporary memory + * allocation while representing a parsed URL. Internally, it contains a single + * normalized URL (the href), and it makes available the components, mostly + * using std::string_view. + */ +struct url_aggregator : url_base { + url_aggregator() = default; + url_aggregator(const url_aggregator &u) = default; + url_aggregator(url_aggregator &&u) noexcept = default; + url_aggregator &operator=(url_aggregator &&u) noexcept = default; + url_aggregator &operator=(const url_aggregator &u) = default; + ~url_aggregator() override = default; + + bool set_href(std::string_view input); + bool set_host(std::string_view input); + bool set_hostname(std::string_view input); + bool set_protocol(std::string_view input); + bool set_username(std::string_view input); + bool set_password(std::string_view input); + bool set_port(std::string_view input); + bool set_pathname(std::string_view input); + void set_search(std::string_view input); + void set_hash(std::string_view input); + + [[nodiscard]] bool has_valid_domain() const noexcept override; + /** + * The origin getter steps are to return the serialization of this's URL's + * origin. [HTML] + * @return a newly allocated string. + * @see https://url.spec.whatwg.org/#concept-url-origin + */ + [[nodiscard]] std::string get_origin() const noexcept override; + /** + * Return the normalized string. + * This function does not allocate memory. + * It is highly efficient. + * @return a constant reference to the underlying normalized URL. + * @see https://url.spec.whatwg.org/#dom-url-href + * @see https://url.spec.whatwg.org/#concept-url-serializer + */ + [[nodiscard]] constexpr std::string_view + get_href() const noexcept ada_lifetime_bound; + /** + * The username getter steps are to return this's URL's username. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-username + */ + [[nodiscard]] std::string_view + get_username() const noexcept ada_lifetime_bound; + /** + * The password getter steps are to return this's URL's password. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-password + */ + [[nodiscard]] std::string_view + get_password() const noexcept ada_lifetime_bound; + /** + * Return this's URL's port, serialized. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-port + */ + [[nodiscard]] std::string_view get_port() const noexcept ada_lifetime_bound; + /** + * Return U+0023 (#), followed by this's URL's fragment. + * This function does not allocate memory. + * @return a lightweight std::string_view.. + * @see https://url.spec.whatwg.org/#dom-url-hash + */ + [[nodiscard]] std::string_view get_hash() const noexcept ada_lifetime_bound; + /** + * Return url's host, serialized, followed by U+003A (:) and url's port, + * serialized. + * This function does not allocate memory. + * When there is no host, this function returns the empty view. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-host + */ + [[nodiscard]] std::string_view get_host() const noexcept ada_lifetime_bound; + /** + * Return this's URL's host, serialized. + * This function does not allocate memory. + * When there is no host, this function returns the empty view. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-hostname + */ + [[nodiscard]] std::string_view + get_hostname() const noexcept ada_lifetime_bound; + /** + * The pathname getter steps are to return the result of URL path serializing + * this's URL. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] constexpr std::string_view + get_pathname() const noexcept ada_lifetime_bound; + /** + * Compute the pathname length in bytes without instantiating a view or a + * string. + * @return size of the pathname in bytes + * @see https://url.spec.whatwg.org/#dom-url-pathname + */ + [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept; + /** + * Return U+003F (?), followed by this's URL's query. + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-search + */ + [[nodiscard]] std::string_view get_search() const noexcept ada_lifetime_bound; + /** + * The protocol getter steps are to return this's URL's scheme, followed by + * U+003A (:). + * This function does not allocate memory. + * @return a lightweight std::string_view. + * @see https://url.spec.whatwg.org/#dom-url-protocol + */ + [[nodiscard]] std::string_view + get_protocol() const noexcept ada_lifetime_bound; + + /** + * A URL includes credentials if its username or password is not the empty + * string. + */ + [[nodiscard]] ada_really_inline constexpr bool + has_credentials() const noexcept; + + /** + * Useful for implementing efficient serialization for the URL. + * + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + * + * Inspired after servo/url + * + * @return a constant reference to the underlying component attribute. + * + * @see + * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31 + */ + [[nodiscard]] ada_really_inline const url_components & + get_components() const noexcept; + /** + * Returns a string representation of this URL. + */ + [[nodiscard]] std::string to_string() const override; + /** + * Returns a string diagram of this URL. + */ + [[nodiscard]] std::string to_diagram() const; + + /** + * Verifies that the parsed URL could be valid. Useful for debugging purposes. + * @return true if the URL is valid, otherwise return true of the offsets are + * possible. + */ + [[nodiscard]] constexpr bool validate() const noexcept; + + /** @return true if it has an host but it is the empty string */ + [[nodiscard]] constexpr bool has_empty_hostname() const noexcept; + /** @return true if it has a host (included an empty host) */ + [[nodiscard]] constexpr bool has_hostname() const noexcept; + /** @return true if the URL has a non-empty username */ + [[nodiscard]] constexpr bool has_non_empty_username() const noexcept; + /** @return true if the URL has a non-empty password */ + [[nodiscard]] constexpr bool has_non_empty_password() const noexcept; + /** @return true if the URL has a (non default) port */ + [[nodiscard]] constexpr bool has_port() const noexcept; + /** @return true if the URL has a password */ + [[nodiscard]] constexpr bool has_password() const noexcept; + /** @return true if the URL has a hash component */ + [[nodiscard]] constexpr bool has_hash() const noexcept override; + /** @return true if the URL has a search component */ + [[nodiscard]] constexpr bool has_search() const noexcept override; + + inline void clear_port(); + inline void clear_hash(); + inline void clear_search() override; + +private: + // helper methods + friend void helpers::strip_trailing_spaces_from_opaque_path( + url_aggregator &url) noexcept; + // parse_url methods + friend url_aggregator + parser::parse_url(std::string_view, const url_aggregator *); + + friend url_aggregator + parser::parse_url_impl(std::string_view, + const url_aggregator *); + friend url_aggregator + parser::parse_url_impl(std::string_view, + const url_aggregator *); + // url_pattern methods + template + friend tl::expected, errors> + parse_url_pattern_impl(std::variant input, + const std::string_view *base_url, + const url_pattern_options *options); + + std::string buffer{}; + url_components components{}; + + /** + * Returns true if neither the search, nor the hash nor the pathname + * have been set. + * @return true if the buffer is ready to receive the path. + */ + [[nodiscard]] ada_really_inline bool is_at_path() const noexcept; + + inline void add_authority_slashes_if_needed() noexcept; + + /** + * To optimize performance, you may indicate how much memory to allocate + * within this instance. + */ + constexpr void reserve(uint32_t capacity); + + ada_really_inline size_t parse_port( + std::string_view view, bool check_trailing_content) noexcept override; + + ada_really_inline size_t parse_port(std::string_view view) noexcept override { + return this->parse_port(view, false); + } + + /** + * Return true on success. The 'in_place' parameter indicates whether the + * the string_view input is pointing in the buffer. When in_place is false, + * we must nearly always update the buffer. + * @see https://url.spec.whatwg.org/#concept-ipv4-parser + */ + [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-ipv6-parser + */ + [[nodiscard]] bool parse_ipv6(std::string_view input); + + /** + * Return true on success. + * @see https://url.spec.whatwg.org/#concept-opaque-host-parser + */ + [[nodiscard]] bool parse_opaque_host(std::string_view input); + + ada_really_inline void parse_path(std::string_view input); + + /** + * A URL cannot have a username/password/port if its host is null or the empty + * string, or its scheme is "file". + */ + [[nodiscard]] constexpr bool cannot_have_credentials_or_port() const; + + template + bool set_host_or_hostname(std::string_view input); + + ada_really_inline bool parse_host(std::string_view input); + + inline void update_base_authority(std::string_view base_buffer, + const url_components &base); + inline void update_unencoded_base_hash(std::string_view input); + inline void update_base_hostname(std::string_view input); + inline void update_base_search(std::string_view input); + inline void update_base_search(std::string_view input, + const uint8_t *query_percent_encode_set); + inline void update_base_pathname(std::string_view input); + inline void update_base_username(std::string_view input); + inline void append_base_username(std::string_view input); + inline void update_base_password(std::string_view input); + inline void append_base_password(std::string_view input); + inline void update_base_port(uint32_t input); + inline void append_base_pathname(std::string_view input); + [[nodiscard]] inline uint32_t retrieve_base_port() const; + constexpr void clear_hostname(); + constexpr void clear_password(); + constexpr void clear_pathname() override; + [[nodiscard]] constexpr bool has_dash_dot() const noexcept; + void delete_dash_dot(); + inline void consume_prepared_path(std::string_view input); + template + [[nodiscard]] ada_really_inline bool + parse_scheme_with_colon(std::string_view input); + ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end, + std::string_view input); + [[nodiscard]] constexpr bool has_authority() const noexcept; + constexpr void set_protocol_as_file(); + inline void set_scheme(std::string_view new_scheme) noexcept; + /** + * Fast function to set the scheme from a view with a colon in the + * buffer, does not change type. + */ + inline void set_scheme_from_view_with_colon( + std::string_view new_scheme_with_colon) noexcept; + inline void copy_scheme(const url_aggregator &u) noexcept; + + inline void update_host_to_base_host(const std::string_view input) noexcept; + +}; // url_aggregator + +inline std::ostream &operator<<(std::ostream &out, const url &u); +} // namespace ada + +#endif +/* end file include/ada/url_aggregator.h */ +/* begin file include/ada/url_aggregator-inl.h */ +/** + * @file url_aggregator-inl.h + * @brief Inline functions for url aggregator + */ +#ifndef ADA_URL_AGGREGATOR_INL_H +#define ADA_URL_AGGREGATOR_INL_H + +/* begin file include/ada/unicode-inl.h */ +/** + * @file unicode-inl.h + * @brief Definitions for unicode operations. + */ +#ifndef ADA_UNICODE_INL_H +#define ADA_UNICODE_INL_H + +/** + * Unicode operations. These functions are not part of our public API and may + * change at any time. + * + * private + * @namespace ada::unicode + * @brief Includes the declarations for unicode operations + */ +namespace ada::unicode { +ada_really_inline size_t percent_encode_index(const std::string_view input, + const uint8_t character_set[]) { + const char *data = input.data(); + const size_t size = input.size(); + + // Process 8 bytes at a time using unrolled loop + size_t i = 0; + for (; i + 8 <= size; i += 8) { + unsigned char chunk[8]; + std::memcpy(&chunk, data + i, + 8); // entices compiler to unconditionally process 8 characters + + // Check 8 characters at once + for (size_t j = 0; j < 8; j++) { + if (character_sets::bit_at(character_set, chunk[j])) { + return i + j; + } + } + } + + // Handle remaining bytes + for (; i < size; i++) { + if (character_sets::bit_at(character_set, data[i])) { + return i; + } + } + + return size; +} +} // namespace ada::unicode + +#endif // ADA_UNICODE_INL_H +/* end file include/ada/unicode-inl.h */ + +#include +#include + +namespace ada { + +inline void +url_aggregator::update_base_authority(std::string_view base_buffer, + const ada::url_components &base) { + std::string_view input = base_buffer.substr( + base.protocol_end, base.host_start - base.protocol_end); + ada_log("url_aggregator::update_base_authority ", input); + + bool input_starts_with_dash = input.starts_with("//"); + uint32_t diff = components.host_start - components.protocol_end; + + buffer.erase(components.protocol_end, + components.host_start - components.protocol_end); + components.username_end = components.protocol_end; + + if (input_starts_with_dash) { + input.remove_prefix(2); + diff += 2; // add "//" + buffer.insert(components.protocol_end, "//"); + components.username_end += 2; + } + + size_t password_delimiter = input.find(':'); + + // Check if input contains both username and password by checking the + // delimiter: ":" A typical input that contains authority would be "user:pass" + if (password_delimiter != std::string_view::npos) { + // Insert both username and password + std::string_view username = input.substr(0, password_delimiter); + std::string_view password = input.substr(password_delimiter + 1); + + buffer.insert(components.protocol_end + diff, username); + diff += uint32_t(username.size()); + buffer.insert(components.protocol_end + diff, ":"); + components.username_end = components.protocol_end + diff; + buffer.insert(components.protocol_end + diff + 1, password); + diff += uint32_t(password.size()) + 1; + } else if (!input.empty()) { + // Insert only username + buffer.insert(components.protocol_end + diff, input); + components.username_end = + components.protocol_end + diff + uint32_t(input.size()); + diff += uint32_t(input.size()); + } + + components.host_start += diff; + + if (buffer.size() > base.host_start && buffer[base.host_start] != '@') { + buffer.insert(components.host_start, "@"); + diff++; + } + components.host_end += diff; + components.pathname_start += diff; + if (components.search_start != url_components::omitted) { + components.search_start += diff; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += diff; + } +} + +inline void url_aggregator::update_unencoded_base_hash(std::string_view input) { + ada_log("url_aggregator::update_unencoded_base_hash ", input, " [", + input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(), + " bytes] components.hash_start = ", components.hash_start); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (components.hash_start != url_components::omitted) { + buffer.resize(components.hash_start); + } + components.hash_start = uint32_t(buffer.size()); + buffer += "#"; + bool encoding_required = unicode::percent_encode( + input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer); + // When encoding_required is false, then buffer is left unchanged, and percent + // encoding was not deemed required. + if (!encoding_required) { + buffer.append(input); + } + ada_log("url_aggregator::update_unencoded_base_hash final buffer is '", + buffer, "' [", buffer.size(), " bytes]"); + ADA_ASSERT_TRUE(validate()); +} + +ada_really_inline uint32_t url_aggregator::replace_and_resize( + uint32_t start, uint32_t end, std::string_view input) { + uint32_t current_length = end - start; + uint32_t input_size = uint32_t(input.size()); + uint32_t new_difference = input_size - current_length; + + if (current_length == 0) { + buffer.insert(start, input); + } else if (input_size == current_length) { + buffer.replace(start, input_size, input); + } else if (input_size < current_length) { + buffer.erase(start, current_length - input_size); + buffer.replace(start, input_size, input); + } else { + buffer.replace(start, current_length, input.substr(0, current_length)); + buffer.insert(start + current_length, input.substr(current_length)); + } + + return new_difference; +} + +inline void url_aggregator::update_base_hostname(const std::string_view input) { + ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(), + " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]"); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + + // This next line is required for when parsing a URL like `foo://` + add_authority_slashes_if_needed(); + + bool has_credentials = components.protocol_end + 2 < components.host_start; + uint32_t new_difference = + replace_and_resize(components.host_start, components.host_end, input); + + if (has_credentials) { + buffer.insert(components.host_start, "@"); + new_difference++; + } + components.host_end += new_difference; + components.pathname_start += new_difference; + if (components.search_start != url_components::omitted) { + components.search_start += new_difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += new_difference; + } + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] ada_really_inline uint32_t +url_aggregator::get_pathname_length() const noexcept { + ada_log("url_aggregator::get_pathname_length"); + uint32_t ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + return ending_index - components.pathname_start; +} + +[[nodiscard]] ada_really_inline bool +url_aggregator::is_at_path() const noexcept { + return buffer.size() == components.pathname_start; +} + +inline void url_aggregator::update_base_search(std::string_view input) { + ada_log("url_aggregator::update_base_search ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (input.empty()) { + clear_search(); + return; + } + + if (input[0] == '?') { + input.remove_prefix(1); + } + + if (components.hash_start == url_components::omitted) { + if (components.search_start == url_components::omitted) { + components.search_start = uint32_t(buffer.size()); + buffer += "?"; + } else { + buffer.resize(components.search_start + 1); + } + + buffer.append(input); + } else { + if (components.search_start == url_components::omitted) { + components.search_start = components.hash_start; + } else { + buffer.erase(components.search_start, + components.hash_start - components.search_start); + components.hash_start = components.search_start; + } + + buffer.insert(components.search_start, "?"); + buffer.insert(components.search_start + 1, input); + components.hash_start += uint32_t(input.size() + 1); // Do not forget `?` + } + + ADA_ASSERT_TRUE(validate()); +} + +inline void +url_aggregator::update_base_search(std::string_view input, + const uint8_t query_percent_encode_set[]) { + ada_log("url_aggregator::update_base_search ", input, + " with encoding parameter ", to_string(), "\n", to_diagram()); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + + if (components.hash_start == url_components::omitted) { + if (components.search_start == url_components::omitted) { + components.search_start = uint32_t(buffer.size()); + buffer += "?"; + } else { + buffer.resize(components.search_start + 1); + } + + bool encoding_required = + unicode::percent_encode(input, query_percent_encode_set, buffer); + // When encoding_required is false, then buffer is left unchanged, and + // percent encoding was not deemed required. + if (!encoding_required) { + buffer.append(input); + } + } else { + if (components.search_start == url_components::omitted) { + components.search_start = components.hash_start; + } else { + buffer.erase(components.search_start, + components.hash_start - components.search_start); + components.hash_start = components.search_start; + } + + buffer.insert(components.search_start, "?"); + size_t idx = + ada::unicode::percent_encode_index(input, query_percent_encode_set); + if (idx == input.size()) { + buffer.insert(components.search_start + 1, input); + components.hash_start += uint32_t(input.size() + 1); // Do not forget `?` + } else { + buffer.insert(components.search_start + 1, input, 0, idx); + input.remove_prefix(idx); + // We only create a temporary string if we need percent encoding and + // we attempt to create as small a temporary string as we can. + std::string encoded = + ada::unicode::percent_encode(input, query_percent_encode_set); + buffer.insert(components.search_start + idx + 1, encoded); + components.hash_start += + uint32_t(encoded.size() + idx + 1); // Do not forget `?` + } + } + + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::update_base_pathname(const std::string_view input) { + ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(), + " bytes] \n", to_diagram()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + ADA_ASSERT_TRUE(validate()); + + const bool begins_with_dashdash = input.starts_with("//"); + if (!begins_with_dashdash && has_dash_dot()) { + // We must delete the ./ + delete_dash_dot(); + } + + if (begins_with_dashdash && !has_opaque_path && !has_authority() && + !has_dash_dot()) { + // If url's host is null, url does not have an opaque path, url's path's + // size is greater than 1, then append U+002F (/) followed by U+002E (.) to + // output. + buffer.insert(components.pathname_start, "/."); + components.pathname_start += 2; + } + + uint32_t difference = replace_and_resize( + components.pathname_start, + components.pathname_start + get_pathname_length(), input); + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::append_base_pathname(const std::string_view input) { + ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(), + "\n", to_diagram()); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); +#if ADA_DEVELOPMENT_CHECKS + // computing the expected password. + std::string path_expected(get_pathname()); + path_expected.append(input); +#endif // ADA_DEVELOPMENT_CHECKS + uint32_t ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + buffer.insert(ending_index, input); + + if (components.search_start != url_components::omitted) { + components.search_start += uint32_t(input.size()); + } + if (components.hash_start != url_components::omitted) { + components.hash_start += uint32_t(input.size()); + } +#if ADA_DEVELOPMENT_CHECKS + std::string path_after = std::string(get_pathname()); + ADA_ASSERT_EQUAL(path_expected, path_after, + "append_base_pathname problem after inserting " + + std::string(input)); +#endif // ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::update_base_username(const std::string_view input) { + ada_log("url_aggregator::update_base_username '", input, "' ", to_string(), + "\n", to_diagram()); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + + add_authority_slashes_if_needed(); + + bool has_password = has_non_empty_password(); + bool host_starts_with_at = buffer.size() > components.host_start && + buffer[components.host_start] == '@'; + uint32_t diff = replace_and_resize(components.protocol_end + 2, + components.username_end, input); + + components.username_end += diff; + components.host_start += diff; + + if (!input.empty() && !host_starts_with_at) { + buffer.insert(components.host_start, "@"); + diff++; + } else if (input.empty() && host_starts_with_at && !has_password) { + // Input is empty, there is no password, and we need to remove "@" from + // hostname + buffer.erase(components.host_start, 1); + diff--; + } + + components.host_end += diff; + components.pathname_start += diff; + if (components.search_start != url_components::omitted) { + components.search_start += diff; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += diff; + } + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::append_base_username(const std::string_view input) { + ada_log("url_aggregator::append_base_username ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); +#if ADA_DEVELOPMENT_CHECKS + // computing the expected password. + std::string username_expected(get_username()); + username_expected.append(input); +#endif // ADA_DEVELOPMENT_CHECKS + add_authority_slashes_if_needed(); + + // If input is empty, do nothing. + if (input.empty()) { + return; + } + + uint32_t difference = uint32_t(input.size()); + buffer.insert(components.username_end, input); + components.username_end += difference; + components.host_start += difference; + + if (buffer[components.host_start] != '@' && + components.host_start != components.host_end) { + buffer.insert(components.host_start, "@"); + difference++; + } + + components.host_end += difference; + components.pathname_start += difference; + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } +#if ADA_DEVELOPMENT_CHECKS + std::string username_after(get_username()); + ADA_ASSERT_EQUAL(username_expected, username_after, + "append_base_username problem after inserting " + + std::string(input)); +#endif // ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_TRUE(validate()); +} + +constexpr void url_aggregator::clear_password() { + ada_log("url_aggregator::clear_password ", to_string()); + ADA_ASSERT_TRUE(validate()); + if (!has_password()) { + return; + } + + uint32_t diff = components.host_start - components.username_end; + buffer.erase(components.username_end, diff); + components.host_start -= diff; + components.host_end -= diff; + components.pathname_start -= diff; + if (components.search_start != url_components::omitted) { + components.search_start -= diff; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= diff; + } +} + +inline void url_aggregator::update_base_password(const std::string_view input) { + ada_log("url_aggregator::update_base_password ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + + add_authority_slashes_if_needed(); + + // TODO: Optimization opportunity. Merge the following removal functions. + if (input.empty()) { + clear_password(); + + // Remove username too, if it is empty. + if (!has_non_empty_username()) { + update_base_username(""); + } + + return; + } + + bool password_exists = has_password(); + uint32_t difference = uint32_t(input.size()); + + if (password_exists) { + uint32_t current_length = + components.host_start - components.username_end - 1; + buffer.erase(components.username_end + 1, current_length); + difference -= current_length; + } else { + buffer.insert(components.username_end, ":"); + difference++; + } + + buffer.insert(components.username_end + 1, input); + components.host_start += difference; + + // The following line is required to add "@" to hostname. When updating + // password if hostname does not start with "@", it is "update_base_password"s + // responsibility to set it. + if (buffer[components.host_start] != '@') { + buffer.insert(components.host_start, "@"); + difference++; + } + + components.host_end += difference; + components.pathname_start += difference; + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::append_base_password(const std::string_view input) { + ada_log("url_aggregator::append_base_password ", input, " ", to_string(), + "\n", to_diagram()); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); +#if ADA_DEVELOPMENT_CHECKS + // computing the expected password. + std::string password_expected = std::string(get_password()); + password_expected.append(input); +#endif // ADA_DEVELOPMENT_CHECKS + add_authority_slashes_if_needed(); + + // If input is empty, do nothing. + if (input.empty()) { + return; + } + + uint32_t difference = uint32_t(input.size()); + if (has_password()) { + buffer.insert(components.host_start, input); + } else { + difference++; // Increment for ":" + buffer.insert(components.username_end, ":"); + buffer.insert(components.username_end + 1, input); + } + components.host_start += difference; + + // The following line is required to add "@" to hostname. When updating + // password if hostname does not start with "@", it is "append_base_password"s + // responsibility to set it. + if (buffer[components.host_start] != '@') { + buffer.insert(components.host_start, "@"); + difference++; + } + + components.host_end += difference; + components.pathname_start += difference; + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } +#if ADA_DEVELOPMENT_CHECKS + std::string password_after(get_password()); + ADA_ASSERT_EQUAL(password_expected, password_after, + "append_base_password problem after inserting " + + std::string(input)); +#endif // ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::update_base_port(uint32_t input) { + ada_log("url_aggregator::update_base_port"); + ADA_ASSERT_TRUE(validate()); + if (input == url_components::omitted) { + clear_port(); + return; + } + // calling std::to_string(input.value()) is unfortunate given that the port + // value is probably already available as a string. + std::string value = helpers::concat(":", std::to_string(input)); + uint32_t difference = uint32_t(value.size()); + + if (components.port != url_components::omitted) { + difference -= components.pathname_start - components.host_end; + buffer.erase(components.host_end, + components.pathname_start - components.host_end); + } + + buffer.insert(components.host_end, value); + components.pathname_start += difference; + if (components.search_start != url_components::omitted) { + components.search_start += difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += difference; + } + components.port = input; + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::clear_port() { + ada_log("url_aggregator::clear_port"); + ADA_ASSERT_TRUE(validate()); + if (components.port == url_components::omitted) { + return; + } + uint32_t length = components.pathname_start - components.host_end; + buffer.erase(components.host_end, length); + components.pathname_start -= length; + if (components.search_start != url_components::omitted) { + components.search_start -= length; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= length; + } + components.port = url_components::omitted; + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const { + ada_log("url_aggregator::retrieve_base_port"); + return components.port; +} + +inline void url_aggregator::clear_search() { + ada_log("url_aggregator::clear_search"); + ADA_ASSERT_TRUE(validate()); + if (components.search_start == url_components::omitted) { + return; + } + + if (components.hash_start == url_components::omitted) { + buffer.resize(components.search_start); + } else { + buffer.erase(components.search_start, + components.hash_start - components.search_start); + components.hash_start = components.search_start; + } + + components.search_start = url_components::omitted; + +#if ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_EQUAL(get_search(), "", + "search should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); +#endif + ADA_ASSERT_TRUE(validate()); +} + +inline void url_aggregator::clear_hash() { + ada_log("url_aggregator::clear_hash"); + ADA_ASSERT_TRUE(validate()); + if (components.hash_start == url_components::omitted) { + return; + } + buffer.resize(components.hash_start); + components.hash_start = url_components::omitted; + +#if ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_EQUAL(get_hash(), "", + "hash should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); +#endif + ADA_ASSERT_TRUE(validate()); +} + +constexpr void url_aggregator::clear_pathname() { + ada_log("url_aggregator::clear_pathname"); + ADA_ASSERT_TRUE(validate()); + uint32_t ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + uint32_t pathname_length = ending_index - components.pathname_start; + buffer.erase(components.pathname_start, pathname_length); + uint32_t difference = pathname_length; + if (components.pathname_start == components.host_end + 2 && + buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') { + components.pathname_start -= 2; + buffer.erase(components.host_end, 2); + difference += 2; + } + if (components.search_start != url_components::omitted) { + components.search_start -= difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= difference; + } + ada_log("url_aggregator::clear_pathname completed, running checks..."); +#if ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_EQUAL(get_pathname(), "", + "pathname should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); +#endif + ADA_ASSERT_TRUE(validate()); + ada_log("url_aggregator::clear_pathname completed, running checks... ok"); +} + +constexpr void url_aggregator::clear_hostname() { + ada_log("url_aggregator::clear_hostname"); + ADA_ASSERT_TRUE(validate()); + if (!has_authority()) { + return; + } + ADA_ASSERT_TRUE(has_authority()); + + uint32_t hostname_length = components.host_end - components.host_start; + uint32_t start = components.host_start; + + // If hostname starts with "@", we should not remove that character. + if (hostname_length > 0 && buffer[start] == '@') { + start++; + hostname_length--; + } + buffer.erase(start, hostname_length); + components.host_end = start; + components.pathname_start -= hostname_length; + if (components.search_start != url_components::omitted) { + components.search_start -= hostname_length; + } + if (components.hash_start != url_components::omitted) { + components.hash_start -= hostname_length; + } +#if ADA_DEVELOPMENT_CHECKS + ADA_ASSERT_EQUAL(get_hostname(), "", + "hostname should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); +#endif + ADA_ASSERT_TRUE(has_authority()); + ADA_ASSERT_EQUAL(has_empty_hostname(), true, + "hostname should have been cleared on buffer=" + buffer + + " with " + components.to_string() + "\n" + to_diagram()); + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] constexpr bool url_aggregator::has_hash() const noexcept { + ada_log("url_aggregator::has_hash"); + return components.hash_start != url_components::omitted; +} + +[[nodiscard]] constexpr bool url_aggregator::has_search() const noexcept { + ada_log("url_aggregator::has_search"); + return components.search_start != url_components::omitted; +} + +constexpr bool url_aggregator::has_credentials() const noexcept { + ada_log("url_aggregator::has_credentials"); + return has_non_empty_username() || has_non_empty_password(); +} + +constexpr bool url_aggregator::cannot_have_credentials_or_port() const { + ada_log("url_aggregator::cannot_have_credentials_or_port"); + return type == ada::scheme::type::FILE || + components.host_start == components.host_end; +} + +[[nodiscard]] ada_really_inline const ada::url_components & +url_aggregator::get_components() const noexcept { + return components; +} + +[[nodiscard]] constexpr bool +ada::url_aggregator::has_authority() const noexcept { + ada_log("url_aggregator::has_authority"); + // Performance: instead of doing this potentially expensive check, we could + // have a boolean in the struct. + return components.protocol_end + 2 <= components.host_start && + helpers::substring(buffer, components.protocol_end, + components.protocol_end + 2) == "//"; +} + +inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept { + ada_log("url_aggregator::add_authority_slashes_if_needed"); + ADA_ASSERT_TRUE(validate()); + // Protocol setter will insert `http:` to the URL. It is up to hostname setter + // to insert + // `//` initially to the buffer, since it depends on the hostname existence. + if (has_authority()) { + return; + } + // Performance: the common case is components.protocol_end == buffer.size() + // Optimization opportunity: in many cases, the "//" is part of the input and + // the insert could be fused with another insert. + buffer.insert(components.protocol_end, "//"); + components.username_end += 2; + components.host_start += 2; + components.host_end += 2; + components.pathname_start += 2; + if (components.search_start != url_components::omitted) { + components.search_start += 2; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += 2; + } + ADA_ASSERT_TRUE(validate()); +} + +constexpr void ada::url_aggregator::reserve(uint32_t capacity) { + buffer.reserve(capacity); +} + +constexpr bool url_aggregator::has_non_empty_username() const noexcept { + ada_log("url_aggregator::has_non_empty_username"); + return components.protocol_end + 2 < components.username_end; +} + +constexpr bool url_aggregator::has_non_empty_password() const noexcept { + ada_log("url_aggregator::has_non_empty_password"); + return components.host_start - components.username_end > 0; +} + +constexpr bool url_aggregator::has_password() const noexcept { + ada_log("url_aggregator::has_password"); + // This function does not care about the length of the password + return components.host_start > components.username_end && + buffer[components.username_end] == ':'; +} + +constexpr bool url_aggregator::has_empty_hostname() const noexcept { + if (!has_hostname()) { + return false; + } + if (components.host_start == components.host_end) { + return true; + } + if (components.host_end > components.host_start + 1) { + return false; + } + return components.username_end != components.host_start; +} + +constexpr bool url_aggregator::has_hostname() const noexcept { + return has_authority(); +} + +constexpr bool url_aggregator::has_port() const noexcept { + ada_log("url_aggregator::has_port"); + // A URL cannot have a username/password/port if its host is null or the empty + // string, or its scheme is "file". + return has_hostname() && components.pathname_start != components.host_end; +} + +[[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept { + // If url's host is null, url does not have an opaque path, url's path's size + // is greater than 1, and url's path[0] is the empty string, then append + // U+002F (/) followed by U+002E (.) to output. + ada_log("url_aggregator::has_dash_dot"); +#if ADA_DEVELOPMENT_CHECKS + // If pathname_start and host_end are exactly two characters apart, then we + // either have a one-digit port such as http://test.com:5?param=1 or else we + // have a /.: sequence such as "non-spec:/.//". We test that this is the case. + if (components.pathname_start == components.host_end + 2) { + ADA_ASSERT_TRUE((buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') || + (buffer[components.host_end] == ':' && + checkers::is_digit(buffer[components.host_end + 1]))); + } + if (components.pathname_start == components.host_end + 2 && + buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') { + ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size()); + ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/'); + ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/'); + } +#endif + // Performance: it should be uncommon for components.pathname_start == + // components.host_end + 2 to be true. So we put this check first in the + // sequence. Most times, we do not have an opaque path. Checking for '/.' is + // more expensive, but should be uncommon. + return components.pathname_start == components.host_end + 2 && + !has_opaque_path && buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.'; +} + +[[nodiscard]] constexpr std::string_view +url_aggregator::get_href() const noexcept ada_lifetime_bound { + ada_log("url_aggregator::get_href"); + return buffer; +} + +ada_really_inline size_t url_aggregator::parse_port( + std::string_view view, bool check_trailing_content) noexcept { + ada_log("url_aggregator::parse_port('", view, "') ", view.size()); + if (!view.empty() && view[0] == '-') { + ada_log("parse_port: view[0] == '0' && view.size() > 1"); + is_valid = false; + return 0; + } + uint16_t parsed_port{}; + auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port); + if (r.ec == std::errc::result_out_of_range) { + ada_log("parse_port: r.ec == std::errc::result_out_of_range"); + is_valid = false; + return 0; + } + ada_log("parse_port: ", parsed_port); + const size_t consumed = size_t(r.ptr - view.data()); + ada_log("parse_port: consumed ", consumed); + if (check_trailing_content) { + is_valid &= + (consumed == view.size() || view[consumed] == '/' || + view[consumed] == '?' || (is_special() && view[consumed] == '\\')); + } + ada_log("parse_port: is_valid = ", is_valid); + if (is_valid) { + ada_log("parse_port", r.ec == std::errc()); + // scheme_default_port can return 0, and we should allow 0 as a base port. + auto default_port = scheme_default_port(); + bool is_port_valid = (default_port == 0 && parsed_port == 0) || + (default_port != parsed_port); + if (r.ec == std::errc() && is_port_valid) { + update_base_port(parsed_port); + } else { + clear_port(); + } + } + return consumed; +} + +constexpr void url_aggregator::set_protocol_as_file() { + ada_log("url_aggregator::set_protocol_as_file "); + ADA_ASSERT_TRUE(validate()); + type = ada::scheme::type::FILE; + // next line could overflow but unsigned arithmetic has well-defined + // overflows. + uint32_t new_difference = 5 - components.protocol_end; + + if (buffer.empty()) { + buffer.append("file:"); + } else { + buffer.erase(0, components.protocol_end); + buffer.insert(0, "file:"); + } + components.protocol_end = 5; + + // Update the rest of the components. + components.username_end += new_difference; + components.host_start += new_difference; + components.host_end += new_difference; + components.pathname_start += new_difference; + if (components.search_start != url_components::omitted) { + components.search_start += new_difference; + } + if (components.hash_start != url_components::omitted) { + components.hash_start += new_difference; + } + ADA_ASSERT_TRUE(validate()); +} + +[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept { + if (!is_valid) { + return true; + } + if (!components.check_offset_consistency()) { + ada_log("url_aggregator::validate inconsistent components \n", + to_diagram()); + return false; + } + // We have a credible components struct, but let us investivate more + // carefully: + /** + * https://user:pass@example.com:1234/foo/bar?baz#quux + * | | | | ^^^^| | | + * | | | | | | | `----- hash_start + * | | | | | | `--------- search_start + * | | | | | `----------------- pathname_start + * | | | | `--------------------- port + * | | | `----------------------- host_end + * | | `---------------------------------- host_start + * | `--------------------------------------- username_end + * `--------------------------------------------- protocol_end + */ + if (components.protocol_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram()); + return false; + } + if (components.username_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted username_end \n", to_diagram()); + return false; + } + if (components.host_start == url_components::omitted) { + ada_log("url_aggregator::validate omitted host_start \n", to_diagram()); + return false; + } + if (components.host_end == url_components::omitted) { + ada_log("url_aggregator::validate omitted host_end \n", to_diagram()); + return false; + } + if (components.pathname_start == url_components::omitted) { + ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram()); + return false; + } + + if (components.protocol_end > buffer.size()) { + ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram()); + return false; + } + if (components.username_end > buffer.size()) { + ada_log("url_aggregator::validate username_end overflow \n", to_diagram()); + return false; + } + if (components.host_start > buffer.size()) { + ada_log("url_aggregator::validate host_start overflow \n", to_diagram()); + return false; + } + if (components.host_end > buffer.size()) { + ada_log("url_aggregator::validate host_end overflow \n", to_diagram()); + return false; + } + if (components.pathname_start > buffer.size()) { + ada_log("url_aggregator::validate pathname_start overflow \n", + to_diagram()); + return false; + } + + if (components.protocol_end > 0) { + if (buffer[components.protocol_end - 1] != ':') { + ada_log( + "url_aggregator::validate missing : at the end of the protocol \n", + to_diagram()); + return false; + } + } + + if (components.username_end != buffer.size() && + components.username_end > components.protocol_end + 2) { + if (buffer[components.username_end] != ':' && + buffer[components.username_end] != '@') { + ada_log( + "url_aggregator::validate missing : or @ at the end of the username " + "\n", + to_diagram()); + return false; + } + } + + if (components.host_start != buffer.size()) { + if (components.host_start > components.username_end) { + if (buffer[components.host_start] != '@') { + ada_log( + "url_aggregator::validate missing @ at the end of the password \n", + to_diagram()); + return false; + } + } else if (components.host_start == components.username_end && + components.host_end > components.host_start) { + if (components.host_start == components.protocol_end + 2) { + if (buffer[components.protocol_end] != '/' || + buffer[components.protocol_end + 1] != '/') { + ada_log( + "url_aggregator::validate missing // between protocol and host " + "\n", + to_diagram()); + return false; + } + } else { + if (components.host_start > components.protocol_end && + buffer[components.host_start] != '@') { + ada_log( + "url_aggregator::validate missing @ at the end of the username " + "\n", + to_diagram()); + return false; + } + } + } else { + if (components.host_end != components.host_start) { + ada_log("url_aggregator::validate expected omitted host \n", + to_diagram()); + return false; + } + } + } + if (components.host_end != buffer.size() && + components.pathname_start > components.host_end) { + if (components.pathname_start == components.host_end + 2 && + buffer[components.host_end] == '/' && + buffer[components.host_end + 1] == '.') { + if (components.pathname_start + 1 >= buffer.size() || + buffer[components.pathname_start] != '/' || + buffer[components.pathname_start + 1] != '/') { + ada_log( + "url_aggregator::validate expected the path to begin with // \n", + to_diagram()); + return false; + } + } else if (buffer[components.host_end] != ':') { + ada_log("url_aggregator::validate missing : at the port \n", + to_diagram()); + return false; + } + } + if (components.pathname_start != buffer.size() && + components.pathname_start < components.search_start && + components.pathname_start < components.hash_start && !has_opaque_path) { + if (buffer[components.pathname_start] != '/') { + ada_log("url_aggregator::validate missing / at the path \n", + to_diagram()); + return false; + } + } + if (components.search_start != url_components::omitted) { + if (buffer[components.search_start] != '?') { + ada_log("url_aggregator::validate missing ? at the search \n", + to_diagram()); + return false; + } + } + if (components.hash_start != url_components::omitted) { + if (buffer[components.hash_start] != '#') { + ada_log("url_aggregator::validate missing # at the hash \n", + to_diagram()); + return false; + } + } + + return true; +} + +[[nodiscard]] constexpr std::string_view +url_aggregator::get_pathname() const noexcept ada_lifetime_bound { + ada_log("url_aggregator::get_pathname pathname_start = ", + components.pathname_start, " buffer.size() = ", buffer.size(), + " components.search_start = ", components.search_start, + " components.hash_start = ", components.hash_start); + auto ending_index = uint32_t(buffer.size()); + if (components.search_start != url_components::omitted) { + ending_index = components.search_start; + } else if (components.hash_start != url_components::omitted) { + ending_index = components.hash_start; + } + return helpers::substring(buffer, components.pathname_start, ending_index); +} + +inline std::ostream &operator<<(std::ostream &out, + const ada::url_aggregator &u) { + return out << u.to_string(); +} + +void url_aggregator::update_host_to_base_host( + const std::string_view input) noexcept { + ada_log("url_aggregator::update_host_to_base_host ", input); + ADA_ASSERT_TRUE(validate()); + ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer)); + if (type != ada::scheme::type::FILE) { + // Let host be the result of host parsing host_view with url is not special. + if (input.empty() && !is_special()) { + if (has_hostname()) { + clear_hostname(); + } else if (has_dash_dot()) { + add_authority_slashes_if_needed(); + delete_dash_dot(); + } + return; + } + } + update_base_hostname(input); + ADA_ASSERT_TRUE(validate()); + return; +} +} // namespace ada + +#endif // ADA_URL_AGGREGATOR_INL_H +/* end file include/ada/url_aggregator-inl.h */ +/* begin file include/ada/url_search_params.h */ +/** + * @file url_search_params.h + * @brief Declaration for the URL Search Params + */ +#ifndef ADA_URL_SEARCH_PARAMS_H +#define ADA_URL_SEARCH_PARAMS_H + +#include +#include +#include +#include + +namespace ada { + +enum class url_search_params_iter_type { + KEYS, + VALUES, + ENTRIES, +}; + +template +struct url_search_params_iter; + +typedef std::pair key_value_view_pair; + +using url_search_params_keys_iter = + url_search_params_iter; +using url_search_params_values_iter = + url_search_params_iter; +using url_search_params_entries_iter = + url_search_params_iter; + +/** + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ +struct url_search_params { + url_search_params() = default; + + /** + * @see + * https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js + */ + explicit url_search_params(const std::string_view input) { + initialize(input); + } + + url_search_params(const url_search_params &u) = default; + url_search_params(url_search_params &&u) noexcept = default; + url_search_params &operator=(url_search_params &&u) noexcept = default; + url_search_params &operator=(const url_search_params &u) = default; + ~url_search_params() = default; + + [[nodiscard]] inline size_t size() const noexcept; + + /** + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-append + */ + inline void append(std::string_view key, std::string_view value); + + /** + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-delete + */ + inline void remove(std::string_view key); + inline void remove(std::string_view key, std::string_view value); + + /** + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get + */ + inline std::optional get(std::string_view key); + + /** + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall + */ + inline std::vector get_all(std::string_view key); + + /** + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has + */ + inline bool has(std::string_view key) noexcept; + inline bool has(std::string_view key, std::string_view value) noexcept; + + /** + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set + */ + inline void set(std::string_view key, std::string_view value); + + /** + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort + */ + inline void sort(); + + /** + * @see https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior + */ + inline std::string to_string() const; + + /** + * Returns a simple JS-style iterator over all of the keys in this + * url_search_params. The keys in the iterator are not unique. The valid + * lifespan of the iterator is tied to the url_search_params. The iterator + * must be freed when you're done with it. + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ + inline url_search_params_keys_iter get_keys(); + + /** + * Returns a simple JS-style iterator over all of the values in this + * url_search_params. The valid lifespan of the iterator is tied to the + * url_search_params. The iterator must be freed when you're done with it. + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ + inline url_search_params_values_iter get_values(); + + /** + * Returns a simple JS-style iterator over all of the entries in this + * url_search_params. The entries are pairs of keys and corresponding values. + * The valid lifespan of the iterator is tied to the url_search_params. The + * iterator must be freed when you're done with it. + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ + inline url_search_params_entries_iter get_entries(); + + /** + * C++ style conventional iterator support. const only because we + * do not really want the params to be modified via the iterator. + */ + inline auto begin() const { return params.begin(); } + inline auto end() const { return params.end(); } + inline auto front() const { return params.front(); } + inline auto back() const { return params.back(); } + inline auto operator[](size_t index) const { return params[index]; } + + /** + * @private + * Used to reset the search params to a new input. + * Used primarily for C API. + * @param input + */ + void reset(std::string_view input); + +private: + typedef std::pair key_value_pair; + std::vector params{}; + + /** + * @see https://url.spec.whatwg.org/#concept-urlencoded-parser + */ + void initialize(std::string_view init); + + template + friend struct url_search_params_iter; +}; // url_search_params + +/** + * Implements a non-conventional iterator pattern that is closer in style to + * JavaScript's definition of an iterator. + * + * @see https://webidl.spec.whatwg.org/#idl-iterable + */ +template +struct url_search_params_iter { + inline url_search_params_iter() : params(EMPTY) {} + url_search_params_iter(const url_search_params_iter &u) = default; + url_search_params_iter(url_search_params_iter &&u) noexcept = default; + url_search_params_iter & + operator=(url_search_params_iter &&u) noexcept = default; + url_search_params_iter &operator=(const url_search_params_iter &u) = default; + ~url_search_params_iter() = default; + + /** + * Return the next item in the iterator or std::nullopt if done. + */ + inline std::optional next(); + + inline bool has_next() const; + +private: + static url_search_params EMPTY; + inline url_search_params_iter(url_search_params ¶ms_) : params(params_) {} + + url_search_params ¶ms; + size_t pos = 0; + + friend struct url_search_params; +}; + +} // namespace ada +#endif +/* end file include/ada/url_search_params.h */ +/* begin file include/ada/url_search_params-inl.h */ +/** + * @file url_search_params-inl.h + * @brief Inline declarations for the URL Search Params + */ +#ifndef ADA_URL_SEARCH_PARAMS_INL_H +#define ADA_URL_SEARCH_PARAMS_INL_H + +#include +#include +#include +#include +#include +#include + +namespace ada { + +// A default, empty url_search_params for use with empty iterators. +template +url_search_params url_search_params_iter::EMPTY; + +inline void url_search_params::reset(std::string_view input) { + params.clear(); + initialize(input); +} + +inline void url_search_params::initialize(std::string_view input) { + if (!input.empty() && input.front() == '?') { + input.remove_prefix(1); + } + + auto process_key_value = [&](const std::string_view current) { + auto equal = current.find('='); + + if (equal == std::string_view::npos) { + std::string name(current); + std::ranges::replace(name, '+', ' '); + params.emplace_back(unicode::percent_decode(name, name.find('%')), ""); + } else { + std::string name(current.substr(0, equal)); + std::string value(current.substr(equal + 1)); + + std::ranges::replace(name, '+', ' '); + std::ranges::replace(value, '+', ' '); + + params.emplace_back(unicode::percent_decode(name, name.find('%')), + unicode::percent_decode(value, value.find('%'))); + } + }; + + while (!input.empty()) { + auto ampersand_index = input.find('&'); + + if (ampersand_index == std::string_view::npos) { + if (!input.empty()) { + process_key_value(input); + } + break; + } else if (ampersand_index != 0) { + process_key_value(input.substr(0, ampersand_index)); + } + + input.remove_prefix(ampersand_index + 1); + } +} + +inline void url_search_params::append(const std::string_view key, + const std::string_view value) { + params.emplace_back(key, value); +} + +inline size_t url_search_params::size() const noexcept { return params.size(); } + +inline std::optional +url_search_params::get(const std::string_view key) { + auto entry = std::ranges::find_if( + params, [&key](const auto ¶m) { return param.first == key; }); + + if (entry == params.end()) { + return std::nullopt; + } + + return entry->second; +} + +inline std::vector +url_search_params::get_all(const std::string_view key) { + std::vector out{}; + + for (auto ¶m : params) { + if (param.first == key) { + out.emplace_back(param.second); + } + } + + return out; +} + +inline bool url_search_params::has(const std::string_view key) noexcept { + auto entry = std::ranges::find_if( + params, [&key](const auto ¶m) { return param.first == key; }); + return entry != params.end(); +} + +inline bool url_search_params::has(std::string_view key, + std::string_view value) noexcept { + auto entry = std::ranges::find_if(params, [&key, &value](const auto ¶m) { + return param.first == key && param.second == value; + }); + return entry != params.end(); +} + +inline std::string url_search_params::to_string() const { + auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE; + std::string out{}; + for (size_t i = 0; i < params.size(); i++) { + auto key = ada::unicode::percent_encode(params[i].first, character_set); + auto value = ada::unicode::percent_encode(params[i].second, character_set); + + // Performance optimization: Move this inside percent_encode. + std::ranges::replace(key, ' ', '+'); + std::ranges::replace(value, ' ', '+'); + + if (i != 0) { + out += "&"; + } + out.append(key); + out += "="; + out.append(value); + } + return out; +} + +inline void url_search_params::set(const std::string_view key, + const std::string_view value) { + const auto find = [&key](const auto ¶m) { return param.first == key; }; + + auto it = std::ranges::find_if(params, find); + + if (it == params.end()) { + params.emplace_back(key, value); + } else { + it->second = value; + params.erase(std::remove_if(std::next(it), params.end(), find), + params.end()); + } +} + +inline void url_search_params::remove(const std::string_view key) { + std::erase_if(params, + [&key](const auto ¶m) { return param.first == key; }); +} + +inline void url_search_params::remove(const std::string_view key, + const std::string_view value) { + std::erase_if(params, [&key, &value](const auto ¶m) { + return param.first == key && param.second == value; + }); +} + +inline void url_search_params::sort() { + std::ranges::stable_sort( + params, [](const key_value_pair &lhs, const key_value_pair &rhs) { + return lhs.first < rhs.first; + }); +} + +inline url_search_params_keys_iter url_search_params::get_keys() { + return url_search_params_keys_iter(*this); +} + +/** + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ +inline url_search_params_values_iter url_search_params::get_values() { + return url_search_params_values_iter(*this); +} + +/** + * @see https://url.spec.whatwg.org/#interface-urlsearchparams + */ +inline url_search_params_entries_iter url_search_params::get_entries() { + return url_search_params_entries_iter(*this); +} + +template +inline bool url_search_params_iter::has_next() const { + return pos < params.params.size(); +} + +template <> +inline std::optional url_search_params_keys_iter::next() { + if (!has_next()) { + return std::nullopt; + } + return params.params[pos++].first; +} + +template <> +inline std::optional url_search_params_values_iter::next() { + if (!has_next()) { + return std::nullopt; + } + return params.params[pos++].second; +} + +template <> +inline std::optional +url_search_params_entries_iter::next() { + if (!has_next()) { + return std::nullopt; + } + return params.params[pos++]; +} + +} // namespace ada + +#endif // ADA_URL_SEARCH_PARAMS_INL_H +/* end file include/ada/url_search_params-inl.h */ +/* begin file include/ada/url_pattern-inl.h */ +/** + * @file url_pattern-inl.h + * @brief Declaration for the URLPattern inline functions. + */ +#ifndef ADA_URL_PATTERN_INL_H +#define ADA_URL_PATTERN_INL_H + +#include + +namespace ada { + +inline bool url_pattern_init::operator==(const url_pattern_init &other) const { + return protocol == other.protocol && username == other.username && + password == other.password && hostname == other.hostname && + port == other.port && search == other.search && hash == other.hash && + pathname == other.pathname; +} + +inline bool url_pattern_component_result::operator==( + const url_pattern_component_result &other) const { + return input == other.input && groups == other.groups; +} + +template +url_pattern_component_result +url_pattern_component::create_component_match_result( + std::string_view input, + std::vector> &&exec_result) { + // Let result be a new URLPatternComponentResult. + // Set result["input"] to input. + // Let groups be a record. + auto result = + url_pattern_component_result{.input = std::string(input), .groups = {}}; + + // Optimization: Let's reserve the size. + result.groups.reserve(exec_result.size()); + + // We explicitly start iterating from 0 even though the spec + // says we should start from 1. This case is handled by the + // std_regex_provider. + for (size_t index = 0; index < exec_result.size(); index++) { + result.groups.insert({ + group_name_list[index], + std::move(exec_result[index]), + }); + } + return result; +} + +template +std::string_view +url_pattern::get_protocol() const ada_lifetime_bound { + // Return this's associated URL pattern's protocol component's pattern string. + return protocol_component.pattern; +} +template +std::string_view +url_pattern::get_username() const ada_lifetime_bound { + // Return this's associated URL pattern's username component's pattern string. + return username_component.pattern; +} +template +std::string_view +url_pattern::get_password() const ada_lifetime_bound { + // Return this's associated URL pattern's password component's pattern string. + return password_component.pattern; +} +template +std::string_view +url_pattern::get_hostname() const ada_lifetime_bound { + // Return this's associated URL pattern's hostname component's pattern string. + return hostname_component.pattern; +} +template +std::string_view +url_pattern::get_port() const ada_lifetime_bound { + // Return this's associated URL pattern's port component's pattern string. + return port_component.pattern; +} +template +std::string_view +url_pattern::get_pathname() const ada_lifetime_bound { + // Return this's associated URL pattern's pathname component's pattern string. + return pathname_component.pattern; +} +template +std::string_view +url_pattern::get_search() const ada_lifetime_bound { + // Return this's associated URL pattern's search component's pattern string. + return search_component.pattern; +} +template +std::string_view +url_pattern::get_hash() const ada_lifetime_bound { + // Return this's associated URL pattern's hash component's pattern string. + return hash_component.pattern; +} +template +bool url_pattern::ignore_case() const { + return ignore_case_; +} +template +bool url_pattern::has_regexp_groups() const { + // If this's associated URL pattern's has regexp groups, then return true. + return protocol_component.has_regexp_groups || + username_component.has_regexp_groups || + password_component.has_regexp_groups || + hostname_component.has_regexp_groups || + port_component.has_regexp_groups || + pathname_component.has_regexp_groups || + search_component.has_regexp_groups || hash_component.has_regexp_groups; +} + +inline bool url_pattern_part::is_regexp() const noexcept { + return type == url_pattern_part_type::REGEXP; +} + +inline std::string_view +url_pattern_compile_component_options::get_delimiter() const { + if (delimiter) { + return {&delimiter.value(), 1}; + } + return {}; +} + +inline std::string_view +url_pattern_compile_component_options::get_prefix() const { + if (prefix) { + return {&prefix.value(), 1}; + } + return {}; +} + +template +template +tl::expected, errors> +url_pattern_component::compile( + std::string_view input, F &encoding_callback, + url_pattern_compile_component_options &options) { + ada_log("url_pattern_component::compile input: ", input); + // Let part list be the result of running parse a pattern string given input, + // options, and encoding callback. + auto part_list = url_pattern_helpers::parse_pattern_string(input, options, + encoding_callback); + + if (!part_list) { + ada_log("parse_pattern_string failed"); + return tl::unexpected(part_list.error()); + } + + // Let (regular expression string, name list) be the result of running + // generate a regular expression and name list given part list and options. + auto [regular_expression_string, name_list] = + url_pattern_helpers::generate_regular_expression_and_name_list(*part_list, + options); + + ada_log("regular expression string: ", regular_expression_string); + + // Let pattern string be the result of running generate a pattern + // string given part list and options. + auto pattern_string = + url_pattern_helpers::generate_pattern_string(*part_list, options); + + // Let regular expression be RegExpCreate(regular expression string, + // flags). If this throws an exception, catch it, and throw a + // TypeError. + std::optional regular_expression = + regex_provider::create_instance(regular_expression_string, + options.ignore_case); + + if (!regular_expression) { + return tl::unexpected(errors::type_error); + } + + // For each part of part list: + // - If part’s type is "regexp", then set has regexp groups to true. + const auto has_regexp = [](const auto &part) { return part.is_regexp(); }; + const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp); + + ada_log("has regexp groups: ", has_regexp_groups); + + // Return a new component whose pattern string is pattern string, regular + // expression is regular expression, group name list is name list, and has + // regexp groups is has regexp groups. + return url_pattern_component( + std::move(pattern_string), std::move(*regular_expression), + std::move(name_list), has_regexp_groups); +} + +template +result> +url_pattern::exec(const url_pattern_input &input, + const std::string_view *base_url) { + // Return the result of match given this's associated URL pattern, input, and + // baseURL if given. + return match(input, base_url); +} + +template +result +url_pattern::test(const url_pattern_input &input, + const std::string_view *base_url) { + // TODO: Optimization opportunity. Rather than returning `url_pattern_result` + // Implement a fast path just like `can_parse()` in ada_url. + // Let result be the result of match given this's associated URL pattern, + // input, and baseURL if given. + // If result is null, return false. + if (auto result = match(input, base_url); result.has_value()) { + return result->has_value(); + } + return tl::unexpected(errors::type_error); +} + +template +result> +url_pattern::match(const url_pattern_input &input, + const std::string_view *base_url_string) { + std::string protocol{}; + std::string username{}; + std::string password{}; + std::string hostname{}; + std::string port{}; + std::string pathname{}; + std::string search{}; + std::string hash{}; + + // Let inputs be an empty list. + // Append input to inputs. + std::vector inputs{input}; + + // If input is a URLPatternInit then: + if (std::holds_alternative(input)) { + ada_log( + "url_pattern::match called with url_pattern_init and base_url_string=", + base_url_string); + // If baseURLString was given, throw a TypeError. + if (base_url_string) { + ada_log("failed to match because base_url_string was given"); + return tl::unexpected(errors::type_error); + } + + // Let applyResult be the result of process a URLPatternInit given input, + // "url", protocol, username, password, hostname, port, pathname, search, + // and hash. + auto apply_result = url_pattern_init::process( + std::get(input), "url", protocol, username, password, + hostname, port, pathname, search, hash); + + // If this throws an exception, catch it, and return null. + if (!apply_result.has_value()) { + ada_log("match returned std::nullopt because process threw"); + return std::nullopt; + } + + // Set protocol to applyResult["protocol"]. + ADA_ASSERT_TRUE(apply_result->protocol.has_value()); + protocol = apply_result->protocol.value(); + + // Set username to applyResult["username"]. + ADA_ASSERT_TRUE(apply_result->username.has_value()); + username = apply_result->username.value(); + + // Set password to applyResult["password"]. + ADA_ASSERT_TRUE(apply_result->password.has_value()); + password = apply_result->password.value(); + + // Set hostname to applyResult["hostname"]. + ADA_ASSERT_TRUE(apply_result->hostname.has_value()); + hostname = apply_result->hostname.value(); + + // Set port to applyResult["port"]. + ADA_ASSERT_TRUE(apply_result->port.has_value()); + port = apply_result->port.value(); + + // Set pathname to applyResult["pathname"]. + ADA_ASSERT_TRUE(apply_result->pathname.has_value()); + pathname = apply_result->pathname.value(); + + // Set search to applyResult["search"]. + ADA_ASSERT_TRUE(apply_result->search.has_value()); + if (apply_result->search->starts_with("?")) { + search = apply_result->search->substr(1); + } else { + search = apply_result->search.value(); + } + + // Set hash to applyResult["hash"]. + ADA_ASSERT_TRUE(apply_result->hash.has_value()); + ADA_ASSERT_TRUE(!apply_result->hash->starts_with("#")); + hash = apply_result->hash.value(); + } else { + ADA_ASSERT_TRUE(std::holds_alternative(input)); + + // Let baseURL be null. + result base_url; + + // If baseURLString was given, then: + if (base_url_string) { + // Let baseURL be the result of parsing baseURLString. + base_url = ada::parse(*base_url_string, nullptr); + + // If baseURL is failure, return null. + if (!base_url) { + ada_log("match returned std::nullopt because failed to parse base_url=", + *base_url_string); + return std::nullopt; + } + + // Append baseURLString to inputs. + inputs.emplace_back(*base_url_string); + } + + url_aggregator *base_url_value = + base_url.has_value() ? &base_url.value() : nullptr; + + // Set url to the result of parsing input given baseURL. + auto url = ada::parse(std::get(input), + base_url_value); + + // If url is failure, return null. + if (!url) { + ada_log("match returned std::nullopt because url failed"); + return std::nullopt; + } + + // Set protocol to url’s scheme. + // IMPORTANT: Not documented on the URLPattern spec, but protocol suffix ':' + // is removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2038 + protocol = url->get_protocol().substr(0, url->get_protocol().size() - 1); + // Set username to url’s username. + username = url->get_username(); + // Set password to url’s password. + password = url->get_password(); + // Set hostname to url’s host, serialized, or the empty string if the value + // is null. + hostname = url->get_hostname(); + // Set port to url’s port, serialized, or the empty string if the value is + // null. + port = url->get_port(); + // Set pathname to the result of URL path serializing url. + pathname = url->get_pathname(); + // Set search to url’s query or the empty string if the value is null. + // IMPORTANT: Not documented on the URLPattern spec, but search prefix '?' + // is removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2232 + if (url->has_search()) { + ADA_ASSERT_TRUE(url->get_search().starts_with("?")); + search = url->get_search().substr(1); + } else { + search = ""; + } + // Set hash to url’s fragment or the empty string if the value is null. + // IMPORTANT: Not documented on the URLPattern spec, but hash prefix '#' is + // removed. Similar work was done on workerd: + // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2242 + if (url->has_hash()) { + ADA_ASSERT_TRUE(url->get_hash().starts_with("#")); + hash = url->get_hash().substr(1); + } else { + hash = ""; + } + } + + // Let protocolExecResult be RegExpBuiltinExec(urlPattern’s protocol + // component's regular expression, protocol). + auto protocol_exec_result = + regex_provider::regex_search(protocol, protocol_component.regexp); + + // Let usernameExecResult be RegExpBuiltinExec(urlPattern’s username + // component's regular expression, username). + auto username_exec_result = + regex_provider::regex_search(username, username_component.regexp); + + // Let passwordExecResult be RegExpBuiltinExec(urlPattern’s password + // component's regular expression, password). + auto password_exec_result = + regex_provider::regex_search(password, password_component.regexp); + + // Let hostnameExecResult be RegExpBuiltinExec(urlPattern’s hostname + // component's regular expression, hostname). + auto hostname_exec_result = + regex_provider::regex_search(hostname, hostname_component.regexp); + + // Let portExecResult be RegExpBuiltinExec(urlPattern’s port component's + // regular expression, port). + auto port_exec_result = + regex_provider::regex_search(port, port_component.regexp); + + // Let pathnameExecResult be RegExpBuiltinExec(urlPattern’s pathname + // component's regular expression, pathname). + auto pathname_exec_result = + regex_provider::regex_search(pathname, pathname_component.regexp); + + // Let searchExecResult be RegExpBuiltinExec(urlPattern’s search component's + // regular expression, search). + auto search_exec_result = + regex_provider::regex_search(search, search_component.regexp); + + // Let hashExecResult be RegExpBuiltinExec(urlPattern’s hash component's + // regular expression, hash). + auto hash_exec_result = + regex_provider::regex_search(hash, hash_component.regexp); + + // If protocolExecResult, usernameExecResult, passwordExecResult, + // hostnameExecResult, portExecResult, pathnameExecResult, searchExecResult, + // or hashExecResult are null then return null. + if (!protocol_exec_result || !username_exec_result || !password_exec_result || + !hostname_exec_result || !port_exec_result || !pathname_exec_result || + !search_exec_result || !hash_exec_result) { + return std::nullopt; + } + + // Let result be a new URLPatternResult. + auto result = url_pattern_result{}; + // Set result["inputs"] to inputs. + result.inputs = std::move(inputs); + // Set result["protocol"] to the result of creating a component match result + // given urlPattern’s protocol component, protocol, and protocolExecResult. + result.protocol = protocol_component.create_component_match_result( + protocol, std::move(*protocol_exec_result)); + + // Set result["username"] to the result of creating a component match result + // given urlPattern’s username component, username, and usernameExecResult. + result.username = username_component.create_component_match_result( + username, std::move(*username_exec_result)); + + // Set result["password"] to the result of creating a component match result + // given urlPattern’s password component, password, and passwordExecResult. + result.password = password_component.create_component_match_result( + password, std::move(*password_exec_result)); + + // Set result["hostname"] to the result of creating a component match result + // given urlPattern’s hostname component, hostname, and hostnameExecResult. + result.hostname = hostname_component.create_component_match_result( + hostname, std::move(*hostname_exec_result)); + + // Set result["port"] to the result of creating a component match result given + // urlPattern’s port component, port, and portExecResult. + result.port = port_component.create_component_match_result( + port, std::move(*port_exec_result)); + + // Set result["pathname"] to the result of creating a component match result + // given urlPattern’s pathname component, pathname, and pathnameExecResult. + result.pathname = pathname_component.create_component_match_result( + pathname, std::move(*pathname_exec_result)); + + // Set result["search"] to the result of creating a component match result + // given urlPattern’s search component, search, and searchExecResult. + result.search = search_component.create_component_match_result( + search, std::move(*search_exec_result)); + + // Set result["hash"] to the result of creating a component match result given + // urlPattern’s hash component, hash, and hashExecResult. + result.hash = hash_component.create_component_match_result( + hash, std::move(*hash_exec_result)); + + return result; +} + +} // namespace ada + +#endif +/* end file include/ada/url_pattern-inl.h */ +/* begin file include/ada/url_pattern_helpers-inl.h */ +/** + * @file url_pattern_helpers-inl.h + * @brief Declaration for the URLPattern helpers. + */ +#ifndef ADA_URL_PATTERN_HELPERS_INL_H +#define ADA_URL_PATTERN_HELPERS_INL_H + +#include +#include + +namespace ada::url_pattern_helpers { +inline std::string to_string(token_type type) { + switch (type) { + case token_type::INVALID_CHAR: + return "INVALID_CHAR"; + case token_type::OPEN: + return "OPEN"; + case token_type::CLOSE: + return "CLOSE"; + case token_type::REGEXP: + return "REGEXP"; + case token_type::NAME: + return "NAME"; + case token_type::CHAR: + return "CHAR"; + case token_type::ESCAPED_CHAR: + return "ESCAPED_CHAR"; + case token_type::OTHER_MODIFIER: + return "OTHER_MODIFIER"; + case token_type::ASTERISK: + return "ASTERISK"; + case token_type::END: + return "END"; + default: + ada::unreachable(); + } +} + +template +void constructor_string_parser::rewind() { + // Set parser’s token index to parser’s component start. + token_index = component_start; + // Set parser’s token increment to 0. + token_increment = 0; +} + +template +bool constructor_string_parser::is_hash_prefix() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index and "#". + return is_non_special_pattern_char(token_index, "#"); +} + +template +bool constructor_string_parser::is_search_prefix() { + // If result of running is a non-special pattern char given parser, parser’s + // token index and "?" is true, then return true. + if (is_non_special_pattern_char(token_index, "?")) { + return true; + } + + // If parser’s token list[parser’s token index]'s value is not "?", then + // return false. + if (token_list[token_index].value != "?") { + return false; + } + + // If previous index is less than 0, then return true. + if (token_index == 0) + return true; + // Let previous index be parser’s token index − 1. + auto previous_index = token_index - 1; + // Let previous token be the result of running get a safe token given parser + // and previous index. + auto previous_token = get_safe_token(previous_index); + ADA_ASSERT_TRUE(previous_token); + // If any of the following are true, then return false: + // - previous token’s type is "name". + // - previous token’s type is "regexp". + // - previous token’s type is "close". + // - previous token’s type is "asterisk". + return !(previous_token->type == token_type::NAME || + previous_token->type == token_type::REGEXP || + previous_token->type == token_type::CLOSE || + previous_token->type == token_type::ASTERISK); +} + +template +bool constructor_string_parser::is_non_special_pattern_char( + size_t index, std::string_view value) { + // Let token be the result of running get a safe token given parser and index. + auto token = get_safe_token(index); + ADA_ASSERT_TRUE(token); + + // If token’s value is not value, then return false. + if (token->value != value) { + return false; + } + + // If any of the following are true: + // - token’s type is "char"; + // - token’s type is "escaped-char"; or + // - token’s type is "invalid-char", + // - then return true. + return token->type == token_type::CHAR || + token->type == token_type::ESCAPED_CHAR || + token->type == token_type::INVALID_CHAR; +} + +template +const token * +constructor_string_parser::get_safe_token(size_t index) { + // If index is less than parser’s token list's size, then return parser’s + // token list[index]. + if (index < token_list.size()) [[likely]] { + return &token_list[index]; + } + + // Assert: parser’s token list's size is greater than or equal to 1. + ADA_ASSERT_TRUE(!token_list.empty()); + + // Let token be parser’s token list[last index]. + // Assert: token’s type is "end". + ADA_ASSERT_TRUE(token_list.back().type == token_type::END); + + // Return token. + return &token_list.back(); +} + +template +bool constructor_string_parser::is_group_open() const { + // If parser’s token list[parser’s token index]'s type is "open", then return + // true. + return token_list[token_index].type == token_type::OPEN; +} + +template +bool constructor_string_parser::is_group_close() const { + // If parser’s token list[parser’s token index]'s type is "close", then return + // true. + return token_list[token_index].type == token_type::CLOSE; +} + +template +bool constructor_string_parser::next_is_authority_slashes() { + // If the result of running is a non-special pattern char given parser, + // parser’s token index + 1, and "/" is false, then return false. + if (!is_non_special_pattern_char(token_index + 1, "/")) { + return false; + } + // If the result of running is a non-special pattern char given parser, + // parser’s token index + 2, and "/" is false, then return false. + if (!is_non_special_pattern_char(token_index + 2, "/")) { + return false; + } + return true; +} + +template +bool constructor_string_parser::is_protocol_suffix() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and ":". + return is_non_special_pattern_char(token_index, ":"); +} + +template +void constructor_string_parser::change_state(State new_state, + size_t skip) { + // If parser’s state is not "init", not "authority", and not "done", then set + // parser’s result[parser’s state] to the result of running make a component + // string given parser. + if (state != State::INIT && state != State::AUTHORITY && + state != State::DONE) { + auto value = make_component_string(); + // TODO: Simplify this. + switch (state) { + case State::PROTOCOL: { + result.protocol = value; + break; + } + case State::USERNAME: { + result.username = value; + break; + } + case State::PASSWORD: { + result.password = value; + break; + } + case State::HOSTNAME: { + result.hostname = value; + break; + } + case State::PORT: { + result.port = value; + break; + } + case State::PATHNAME: { + result.pathname = value; + break; + } + case State::SEARCH: { + result.search = value; + break; + } + case State::HASH: { + result.hash = value; + break; + } + default: + ada::unreachable(); + } + } + + // If parser’s state is not "init" and new state is not "done", then: + if (state != State::INIT && new_state != State::DONE) { + // If parser’s state is "protocol", "authority", "username", or "password"; + // new state is "port", "pathname", "search", or "hash"; and parser’s + // result["hostname"] does not exist, then set parser’s result["hostname"] + // to the empty string. + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD) && + (new_state == State::PORT || new_state == State::PATHNAME || + new_state == State::SEARCH || new_state == State::HASH) && + !result.hostname) + result.hostname = ""; + } + + // If parser’s state is "protocol", "authority", "username", "password", + // "hostname", or "port"; new state is "search" or "hash"; and parser’s + // result["pathname"] does not exist, then: + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD || + state == State::HOSTNAME || state == State::PORT) && + (new_state == State::SEARCH || new_state == State::HASH) && + !result.pathname) { + if (protocol_matches_a_special_scheme_flag) { + result.pathname = "/"; + } else { + // Otherwise, set parser’s result["pathname"] to the empty string. + result.pathname = ""; + } + } + + // If parser’s state is "protocol", "authority", "username", "password", + // "hostname", "port", or "pathname"; new state is "hash"; and parser’s + // result["search"] does not exist, then set parser’s result["search"] to + // the empty string. + if ((state == State::PROTOCOL || state == State::AUTHORITY || + state == State::USERNAME || state == State::PASSWORD || + state == State::HOSTNAME || state == State::PORT || + state == State::PATHNAME) && + new_state == State::HASH && !result.search) { + result.search = ""; + } + + // Set parser’s state to new state. + state = new_state; + // Increment parser’s token index by skip. + token_index += skip; + // Set parser’s component start to parser’s token index. + component_start = token_index; + // Set parser’s token increment to 0. + token_increment = 0; +} + +template +std::string constructor_string_parser::make_component_string() { + // Assert: parser’s token index is less than parser’s token list's size. + ADA_ASSERT_TRUE(token_index < token_list.size()); + + // Let token be parser’s token list[parser’s token index]. + // Let end index be token’s index. + const auto end_index = token_list[token_index].index; + // Let component start token be the result of running get a safe token given + // parser and parser’s component start. + const auto component_start_token = get_safe_token(component_start); + ADA_ASSERT_TRUE(component_start_token); + // Let component start input index be component start token’s index. + const auto component_start_input_index = component_start_token->index; + // Return the code point substring from component start input index to end + // index within parser’s input. + return input.substr(component_start_input_index, + end_index - component_start_input_index); +} + +template +bool constructor_string_parser::is_an_identity_terminator() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and "@". + return is_non_special_pattern_char(token_index, "@"); +} + +template +bool constructor_string_parser::is_pathname_start() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and "/". + return is_non_special_pattern_char(token_index, "/"); +} + +template +bool constructor_string_parser::is_password_prefix() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and ":". + return is_non_special_pattern_char(token_index, ":"); +} + +template +bool constructor_string_parser::is_an_ipv6_open() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and "[". + return is_non_special_pattern_char(token_index, "["); +} + +template +bool constructor_string_parser::is_an_ipv6_close() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and "]". + return is_non_special_pattern_char(token_index, "]"); +} + +template +bool constructor_string_parser::is_port_prefix() { + // Return the result of running is a non-special pattern char given parser, + // parser’s token index, and ":". + return is_non_special_pattern_char(token_index, ":"); +} + +inline void Tokenizer::get_next_code_point() { + ada_log("Tokenizer::get_next_code_point called with index=", next_index); + ADA_ASSERT_TRUE(next_index < input.size()); + // this assumes that we have a valid, non-truncated UTF-8 stream. + code_point = 0; + size_t number_bytes = 0; + unsigned char first_byte = input[next_index]; + + if ((first_byte & 0x80) == 0) { + // 1-byte character (ASCII) + next_index++; + code_point = first_byte; + ada_log("Tokenizer::get_next_code_point returning ASCII code point=", + uint32_t(code_point)); + ada_log("Tokenizer::get_next_code_point next_index =", next_index, + " input.size()=", input.size()); + return; + } + ada_log("Tokenizer::get_next_code_point read first byte=", + uint32_t(first_byte)); + if ((first_byte & 0xE0) == 0xC0) { + code_point = first_byte & 0x1F; + number_bytes = 2; + ada_log("Tokenizer::get_next_code_point two bytes"); + } else if ((first_byte & 0xF0) == 0xE0) { + code_point = first_byte & 0x0F; + number_bytes = 3; + ada_log("Tokenizer::get_next_code_point three bytes"); + } else if ((first_byte & 0xF8) == 0xF0) { + code_point = first_byte & 0x07; + number_bytes = 4; + ada_log("Tokenizer::get_next_code_point four bytes"); + } + ADA_ASSERT_TRUE(number_bytes + next_index <= input.size()); + + for (size_t i = 1 + next_index; i < number_bytes + next_index; ++i) { + unsigned char byte = input[i]; + ada_log("Tokenizer::get_next_code_point read byte=", uint32_t(byte)); + code_point = (code_point << 6) | (byte & 0x3F); + } + ada_log("Tokenizer::get_next_code_point returning non-ASCII code point=", + uint32_t(code_point)); + ada_log("Tokenizer::get_next_code_point next_index =", next_index, + " input.size()=", input.size()); + next_index += number_bytes; +} + +inline void Tokenizer::seek_and_get_next_code_point(size_t new_index) { + ada_log("Tokenizer::seek_and_get_next_code_point called with new_index=", + new_index); + // Set tokenizer’s next index to index. + next_index = new_index; + // Run get the next code point given tokenizer. + get_next_code_point(); +} + +inline void Tokenizer::add_token(token_type type, size_t next_position, + size_t value_position, size_t value_length) { + ada_log("Tokenizer::add_token called with type=", to_string(type), + " next_position=", next_position, " value_position=", value_position); + ADA_ASSERT_TRUE(next_position >= value_position); + + // Let token be a new token. + // Set token’s type to type. + // Set token’s index to tokenizer’s index. + // Set token’s value to the code point substring from value position with + // length value length within tokenizer’s input. + // Append token to the back of tokenizer’s token list. + token_list.emplace_back(type, index, + input.substr(value_position, value_length)); + // Set tokenizer’s index to next position. + index = next_position; +} + +inline void Tokenizer::add_token_with_default_length(token_type type, + size_t next_position, + size_t value_position) { + // Let computed length be next position − value position. + auto computed_length = next_position - value_position; + // Run add a token given tokenizer, type, next position, value position, and + // computed length. + add_token(type, next_position, value_position, computed_length); +} + +inline void Tokenizer::add_token_with_defaults(token_type type) { + ada_log("Tokenizer::add_token_with_defaults called with type=", + to_string(type)); + // Run add a token with default length given tokenizer, type, tokenizer’s next + // index, and tokenizer’s index. + add_token_with_default_length(type, next_index, index); +} + +inline ada_warn_unused std::optional +Tokenizer::process_tokenizing_error(size_t next_position, + size_t value_position) { + // If tokenizer’s policy is "strict", then throw a TypeError. + if (policy == token_policy::strict) { + ada_log("process_tokenizing_error failed with next_position=", + next_position, " value_position=", value_position); + return errors::type_error; + } + // Assert: tokenizer’s policy is "lenient". + ADA_ASSERT_TRUE(policy == token_policy::lenient); + // Run add a token with default length given tokenizer, "invalid-char", next + // position, and value position. + add_token_with_default_length(token_type::INVALID_CHAR, next_position, + value_position); + return std::nullopt; +} + +template +token *url_pattern_parser::try_consume_modifier_token() { + // Let token be the result of running try to consume a token given parser and + // "other-modifier". + auto token = try_consume_token(token_type::OTHER_MODIFIER); + // If token is not null, then return token. + if (token) + return token; + // Set token to the result of running try to consume a token given parser and + // "asterisk". + // Return token. + return try_consume_token(token_type::ASTERISK); +} + +template +token *url_pattern_parser::try_consume_regexp_or_wildcard_token( + const token *name_token) { + // Let token be the result of running try to consume a token given parser and + // "regexp". + auto token = try_consume_token(token_type::REGEXP); + // If name token is null and token is null, then set token to the result of + // running try to consume a token given parser and "asterisk". + if (!name_token && !token) { + token = try_consume_token(token_type::ASTERISK); + } + // Return token. + return token; +} + +template +token *url_pattern_parser::try_consume_token(token_type type) { + ada_log("url_pattern_parser::try_consume_token called with type=", + to_string(type)); + // Assert: parser’s index is less than parser’s token list size. + ADA_ASSERT_TRUE(index < tokens.size()); + // Let next token be parser’s token list[parser’s index]. + auto &next_token = tokens[index]; + // If next token’s type is not type return null. + if (next_token.type != type) + return nullptr; + // Increase parser’s index by 1. + index++; + // Return next token. + return &next_token; +} + +template +std::string url_pattern_parser::consume_text() { + // Let result be the empty string. + std::string result{}; + // While true: + while (true) { + // Let token be the result of running try to consume a token given parser + // and "char". + auto token = try_consume_token(token_type::CHAR); + // If token is null, then set token to the result of running try to consume + // a token given parser and "escaped-char". + if (!token) + token = try_consume_token(token_type::ESCAPED_CHAR); + // If token is null, then break. + if (!token) + break; + // Append token’s value to the end of result. + result.append(token->value); + } + // Return result. + return result; +} + +template +bool url_pattern_parser::consume_required_token(token_type type) { + ada_log("url_pattern_parser::consume_required_token called with type=", + to_string(type)); + // Let result be the result of running try to consume a token given parser and + // type. + return try_consume_token(type) != nullptr; +} + +template +std::optional +url_pattern_parser::maybe_add_part_from_the_pending_fixed_value() { + // If parser’s pending fixed value is the empty string, then return. + if (pending_fixed_value.empty()) { + ada_log("pending_fixed_value is empty"); + return std::nullopt; + } + // Let encoded value be the result of running parser’s encoding callback given + // parser’s pending fixed value. + auto encoded_value = encoding_callback(pending_fixed_value); + if (!encoded_value) { + ada_log("failed to encode pending_fixed_value: ", pending_fixed_value); + return encoded_value.error(); + } + // Set parser’s pending fixed value to the empty string. + pending_fixed_value.clear(); + // Let part be a new part whose type is "fixed-text", value is encoded value, + // and modifier is "none". + // Append part to parser’s part list. + parts.emplace_back(url_pattern_part_type::FIXED_TEXT, + std::move(*encoded_value), + url_pattern_part_modifier::none); + return std::nullopt; +} + +template +std::optional url_pattern_parser::add_part( + std::string_view prefix, token *name_token, token *regexp_or_wildcard_token, + std::string_view suffix, token *modifier_token) { + // Let modifier be "none". + auto modifier = url_pattern_part_modifier::none; + // If modifier token is not null: + if (modifier_token) { + // If modifier token’s value is "?" then set modifier to "optional". + if (modifier_token->value == "?") { + modifier = url_pattern_part_modifier::optional; + } else if (modifier_token->value == "*") { + // Otherwise if modifier token’s value is "*" then set modifier to + // "zero-or-more". + modifier = url_pattern_part_modifier::zero_or_more; + } else if (modifier_token->value == "+") { + // Otherwise if modifier token’s value is "+" then set modifier to + // "one-or-more". + modifier = url_pattern_part_modifier::one_or_more; + } + } + // If name token is null and regexp or wildcard token is null and modifier + // is "none": + if (!name_token && !regexp_or_wildcard_token && + modifier == url_pattern_part_modifier::none) { + // Append prefix to the end of parser’s pending fixed value. + pending_fixed_value.append(prefix); + return std::nullopt; + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = maybe_add_part_from_the_pending_fixed_value()) { + return *error; + } + // If name token is null and regexp or wildcard token is null: + if (!name_token && !regexp_or_wildcard_token) { + // Assert: suffix is the empty string. + ADA_ASSERT_TRUE(suffix.empty()); + // If prefix is the empty string, then return. + if (prefix.empty()) + return std::nullopt; + // Let encoded value be the result of running parser’s encoding callback + // given prefix. + auto encoded_value = encoding_callback(prefix); + if (!encoded_value) { + return encoded_value.error(); + } + // Let part be a new part whose type is "fixed-text", value is encoded + // value, and modifier is modifier. + // Append part to parser’s part list. + parts.emplace_back(url_pattern_part_type::FIXED_TEXT, + std::move(*encoded_value), modifier); + return std::nullopt; + } + // Let regexp value be the empty string. + std::string regexp_value{}; + // If regexp or wildcard token is null, then set regexp value to parser’s + // segment wildcard regexp. + if (!regexp_or_wildcard_token) { + regexp_value = segment_wildcard_regexp; + } else if (regexp_or_wildcard_token->type == token_type::ASTERISK) { + // Otherwise if regexp or wildcard token’s type is "asterisk", then set + // regexp value to the full wildcard regexp value. + regexp_value = ".*"; + } else { + // Otherwise set regexp value to regexp or wildcard token’s value. + regexp_value = regexp_or_wildcard_token->value; + } + // Let type be "regexp". + auto type = url_pattern_part_type::REGEXP; + // If regexp value is parser’s segment wildcard regexp: + if (regexp_value == segment_wildcard_regexp) { + // Set type to "segment-wildcard". + type = url_pattern_part_type::SEGMENT_WILDCARD; + // Set regexp value to the empty string. + regexp_value.clear(); + } else if (regexp_value == ".*") { + // Otherwise if regexp value is the full wildcard regexp value: + // Set type to "full-wildcard". + type = url_pattern_part_type::FULL_WILDCARD; + // Set regexp value to the empty string. + regexp_value.clear(); + } + // Let name be the empty string. + std::string name{}; + // If name token is not null, then set name to name token’s value. + if (name_token) { + name = name_token->value; + } else if (regexp_or_wildcard_token) { + // Otherwise if regexp or wildcard token is not null: + // Set name to parser’s next numeric name, serialized. + // TODO: Make sure this is correct. + name = std::to_string(next_numeric_name); + // Increment parser’s next numeric name by 1. + next_numeric_name++; + } + // If the result of running is a duplicate name given parser and name is + // true, then throw a TypeError. + if (std::ranges::any_of( + parts, [&name](const auto &part) { return part.name == name; })) { + return errors::type_error; + } + // Let encoded prefix be the result of running parser’s encoding callback + // given prefix. + auto encoded_prefix = encoding_callback(prefix); + if (!encoded_prefix) + return encoded_prefix.error(); + // Let encoded suffix be the result of running parser’s encoding callback + // given suffix. + auto encoded_suffix = encoding_callback(suffix); + if (!encoded_suffix) + return encoded_suffix.error(); + // Let part be a new part whose type is type, value is regexp value, + // modifier is modifier, name is name, prefix is encoded prefix, and suffix + // is encoded suffix. + // Append part to parser’s part list. + parts.emplace_back(type, std::move(regexp_value), modifier, std::move(name), + std::move(*encoded_prefix), std::move(*encoded_suffix)); + return std::nullopt; +} + +template +tl::expected, errors> +parse_pattern_string(std::string_view input, + url_pattern_compile_component_options &options, + F &encoding_callback) { + ada_log("parse_pattern_string input=", input); + // Let parser be a new pattern parser whose encoding callback is encoding + // callback and segment wildcard regexp is the result of running generate a + // segment wildcard regexp given options. + auto parser = url_pattern_parser( + encoding_callback, generate_segment_wildcard_regexp(options)); + // Set parser’s token list to the result of running tokenize given input and + // "strict". + auto tokenize_result = tokenize(input, token_policy::strict); + if (!tokenize_result) { + ada_log("parse_pattern_string tokenize failed"); + return tl::unexpected(tokenize_result.error()); + } + parser.tokens = std::move(*tokenize_result); + + // While parser’s index is less than parser’s token list's size: + while (parser.can_continue()) { + // Let char token be the result of running try to consume a token given + // parser and "char". + auto char_token = parser.try_consume_token(token_type::CHAR); + // Let name token be the result of running try to consume a token given + // parser and "name". + auto name_token = parser.try_consume_token(token_type::NAME); + // Let regexp or wildcard token be the result of running try to consume a + // regexp or wildcard token given parser and name token. + auto regexp_or_wildcard_token = + parser.try_consume_regexp_or_wildcard_token(name_token); + // If name token is not null or regexp or wildcard token is not null: + if (name_token || regexp_or_wildcard_token) { + // Let prefix be the empty string. + std::string prefix{}; + // If char token is not null then set prefix to char token’s value. + if (char_token) + prefix = char_token->value; + // If prefix is not the empty string and not options’s prefix code point: + if (!prefix.empty() && prefix != options.get_prefix()) { + // Append prefix to the end of parser’s pending fixed value. + parser.pending_fixed_value.append(prefix); + // Set prefix to the empty string. + prefix.clear(); + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) { + ada_log("maybe_add_part_from_the_pending_fixed_value failed"); + return tl::unexpected(*error); + } + // Let modifier token be the result of running try to consume a modifier + // token given parser. + auto modifier_token = parser.try_consume_modifier_token(); + // Run add a part given parser, prefix, name token, regexp or wildcard + // token, the empty string, and modifier token. + if (auto error = + parser.add_part(prefix, name_token, regexp_or_wildcard_token, "", + modifier_token)) { + ada_log("parser.add_part failed"); + return tl::unexpected(*error); + } + // Continue. + continue; + } + + // Let fixed token be char token. + auto fixed_token = char_token; + // If fixed token is null, then set fixed token to the result of running try + // to consume a token given parser and "escaped-char". + if (!fixed_token) + fixed_token = parser.try_consume_token(token_type::ESCAPED_CHAR); + // If fixed token is not null: + if (fixed_token) { + // Append fixed token’s value to parser’s pending fixed value. + parser.pending_fixed_value.append(fixed_token->value); + // Continue. + continue; + } + // Let open token be the result of running try to consume a token given + // parser and "open". + auto open_token = parser.try_consume_token(token_type::OPEN); + // If open token is not null: + if (open_token) { + // Set prefix be the result of running consume text given parser. + auto prefix_ = parser.consume_text(); + // Set name token to the result of running try to consume a token given + // parser and "name". + name_token = parser.try_consume_token(token_type::NAME); + // Set regexp or wildcard token to the result of running try to consume a + // regexp or wildcard token given parser and name token. + regexp_or_wildcard_token = + parser.try_consume_regexp_or_wildcard_token(name_token); + // Let suffix be the result of running consume text given parser. + auto suffix_ = parser.consume_text(); + // Run consume a required token given parser and "close". + if (!parser.consume_required_token(token_type::CLOSE)) { + ada_log("parser.consume_required_token failed"); + return tl::unexpected(errors::type_error); + } + // Set modifier token to the result of running try to consume a modifier + // token given parser. + auto modifier_token = parser.try_consume_modifier_token(); + // Run add a part given parser, prefix, name token, regexp or wildcard + // token, suffix, and modifier token. + if (auto error = + parser.add_part(prefix_, name_token, regexp_or_wildcard_token, + suffix_, modifier_token)) { + return tl::unexpected(*error); + } + // Continue. + continue; + } + // Run maybe add a part from the pending fixed value given parser. + if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) { + ada_log("maybe_add_part_from_the_pending_fixed_value failed on line 992"); + return tl::unexpected(*error); + } + // Run consume a required token given parser and "end". + if (!parser.consume_required_token(token_type::END)) { + return tl::unexpected(errors::type_error); + } + } + ada_log("parser.parts size is: ", parser.parts.size()); + // Return parser’s part list. + return parser.parts; +} + +template +bool protocol_component_matches_special_scheme( + url_pattern_component &component) { + // let's avoid unnecessary copy here. + auto ®ex = component.regexp; + return regex_provider::regex_match("http", regex) || + regex_provider::regex_match("https", regex) || + regex_provider::regex_match("ws", regex) || + regex_provider::regex_match("wss", regex) || + regex_provider::regex_match("ftp", regex); +} + +template +inline std::optional constructor_string_parser< + regex_provider>::compute_protocol_matches_special_scheme_flag() { + ada_log("constructor_string_parser::compute_protocol_matches_special_scheme_" + "flag"); + // Let protocol string be the result of running make a component string given + // parser. + auto protocol_string = make_component_string(); + // Let protocol component be the result of compiling a component given + // protocol string, canonicalize a protocol, and default options. + auto protocol_component = url_pattern_component::compile( + protocol_string, canonicalize_protocol, + url_pattern_compile_component_options::DEFAULT); + if (!protocol_component) { + ada_log("url_pattern_component::compile failed for protocol_string ", + protocol_string); + return protocol_component.error(); + } + // If the result of running protocol component matches a special scheme given + // protocol component is true, then set parser’s protocol matches a special + // scheme flag to true. + if (protocol_component_matches_special_scheme(*protocol_component)) { + protocol_matches_a_special_scheme_flag = true; + } + return std::nullopt; +} + +template +tl::expected +constructor_string_parser::parse(std::string_view input) { + ada_log("constructor_string_parser::parse input=", input); + // Let parser be a new constructor string parser whose input is input and + // token list is the result of running tokenize given input and "lenient". + auto token_list = tokenize(input, token_policy::lenient); + if (!token_list) { + return tl::unexpected(token_list.error()); + } + auto parser = constructor_string_parser(input, std::move(*token_list)); + + // While parser’s token index is less than parser’s token list size: + while (parser.token_index < parser.token_list.size()) { + // Set parser’s token increment to 1. + parser.token_increment = 1; + + // If parser’s token list[parser’s token index]'s type is "end" then: + if (parser.token_list[parser.token_index].type == token_type::END) { + // If parser’s state is "init": + if (parser.state == State::INIT) { + // Run rewind given parser. + parser.rewind(); + // If the result of running is a hash prefix given parser is true, then + // run change state given parser, "hash" and 1. + if (parser.is_hash_prefix()) { + parser.change_state(State::HASH, 1); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true: Run change state given parser, "search" and 1. + parser.change_state(State::SEARCH, 1); + } else { + // Run change state given parser, "pathname" and 0. + parser.change_state(State::PATHNAME, 0); + } + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + // Continue. + continue; + } + + if (parser.state == State::AUTHORITY) { + // If parser’s state is "authority": + // Run rewind and set state given parser, and "hostname". + parser.rewind(); + parser.change_state(State::HOSTNAME, 0); + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + // Continue. + continue; + } + + // Run change state given parser, "done" and 0. + parser.change_state(State::DONE, 0); + // Break. + break; + } + + // If the result of running is a group open given parser is true: + if (parser.is_group_open()) { + // Increment parser’s group depth by 1. + parser.group_depth += 1; + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + } + + // If parser’s group depth is greater than 0: + if (parser.group_depth > 0) { + // If the result of running is a group close given parser is true, then + // decrement parser’s group depth by 1. + if (parser.is_group_close()) { + parser.group_depth -= 1; + } else { + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + continue; + } + } + + // Switch on parser’s state and run the associated steps: + switch (parser.state) { + case State::INIT: { + // If the result of running is a protocol suffix given parser is true: + if (parser.is_protocol_suffix()) { + // Run rewind and set state given parser and "protocol". + parser.rewind(); + parser.change_state(State::PROTOCOL, 0); + } + break; + } + case State::PROTOCOL: { + // If the result of running is a protocol suffix given parser is true: + if (parser.is_protocol_suffix()) { + // Run compute protocol matches a special scheme flag given parser. + if (const auto error = + parser.compute_protocol_matches_special_scheme_flag()) { + ada_log("compute_protocol_matches_special_scheme_flag failed"); + return tl::unexpected(*error); + } + // Let next state be "pathname". + auto next_state = State::PATHNAME; + // Let skip be 1. + auto skip = 1; + // If the result of running next is authority slashes given parser is + // true: + if (parser.next_is_authority_slashes()) { + // Set next state to "authority". + next_state = State::AUTHORITY; + // Set skip to 3. + skip = 3; + } else if (parser.protocol_matches_a_special_scheme_flag) { + // Otherwise if parser’s protocol matches a special scheme flag is + // true, then set next state to "authority". + next_state = State::AUTHORITY; + } + + // Run change state given parser, next state, and skip. + parser.change_state(next_state, skip); + } + break; + } + case State::AUTHORITY: { + // If the result of running is an identity terminator given parser is + // true, then run rewind and set state given parser and "username". + if (parser.is_an_identity_terminator()) { + parser.rewind(); + parser.change_state(State::USERNAME, 0); + } else if (parser.is_pathname_start() || parser.is_search_prefix() || + parser.is_hash_prefix()) { + // Otherwise if any of the following are true: + // - the result of running is a pathname start given parser; + // - the result of running is a search prefix given parser; or + // - the result of running is a hash prefix given parser, + // then run rewind and set state given parser and "hostname". + parser.rewind(); + parser.change_state(State::HOSTNAME, 0); + } + break; + } + case State::USERNAME: { + // If the result of running is a password prefix given parser is true, + // then run change state given parser, "password", and 1. + if (parser.is_password_prefix()) { + parser.change_state(State::PASSWORD, 1); + } else if (parser.is_an_identity_terminator()) { + // Otherwise if the result of running is an identity terminator given + // parser is true, then run change state given parser, "hostname", + // and 1. + parser.change_state(State::HOSTNAME, 1); + } + break; + } + case State::PASSWORD: { + // If the result of running is an identity terminator given parser is + // true, then run change state given parser, "hostname", and 1. + if (parser.is_an_identity_terminator()) { + parser.change_state(State::HOSTNAME, 1); + } + break; + } + case State::HOSTNAME: { + // If the result of running is an IPv6 open given parser is true, then + // increment parser’s hostname IPv6 bracket depth by 1. + if (parser.is_an_ipv6_open()) { + parser.hostname_ipv6_bracket_depth += 1; + } else if (parser.is_an_ipv6_close()) { + // Otherwise if the result of running is an IPv6 close given parser is + // true, then decrement parser’s hostname IPv6 bracket depth by 1. + parser.hostname_ipv6_bracket_depth -= 1; + } else if (parser.is_port_prefix() && + parser.hostname_ipv6_bracket_depth == 0) { + // Otherwise if the result of running is a port prefix given parser is + // true and parser’s hostname IPv6 bracket depth is zero, then run + // change state given parser, "port", and 1. + parser.change_state(State::PORT, 1); + } else if (parser.is_pathname_start()) { + // Otherwise if the result of running is a pathname start given parser + // is true, then run change state given parser, "pathname", and 0. + parser.change_state(State::PATHNAME, 0); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true, then run change state given parser, "search", and 1. + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + + break; + } + case State::PORT: { + // If the result of running is a pathname start given parser is true, + // then run change state given parser, "pathname", and 0. + if (parser.is_pathname_start()) { + parser.change_state(State::PATHNAME, 0); + } else if (parser.is_search_prefix()) { + // Otherwise if the result of running is a search prefix given parser + // is true, then run change state given parser, "search", and 1. + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + break; + } + case State::PATHNAME: { + // If the result of running is a search prefix given parser is true, + // then run change state given parser, "search", and 1. + if (parser.is_search_prefix()) { + parser.change_state(State::SEARCH, 1); + } else if (parser.is_hash_prefix()) { + // Otherwise if the result of running is a hash prefix given parser is + // true, then run change state given parser, "hash", and 1. + parser.change_state(State::HASH, 1); + } + break; + } + case State::SEARCH: { + // If the result of running is a hash prefix given parser is true, then + // run change state given parser, "hash", and 1. + if (parser.is_hash_prefix()) { + parser.change_state(State::HASH, 1); + } + } + case State::HASH: { + // Do nothing + break; + } + default: { + // Assert: This step is never reached. + unreachable(); + } + } + + // Increment parser’s token index by parser’s token increment. + parser.token_index += parser.token_increment; + } + + // If parser’s result contains "hostname" and not "port", then set parser’s + // result["port"] to the empty string. + if (parser.result.hostname && !parser.result.port) { + parser.result.port = ""; + } + + // Return parser’s result. + return parser.result; +} + +} // namespace ada::url_pattern_helpers + +#endif +/* end file include/ada/url_pattern_helpers-inl.h */ + +// Public API +/* begin file include/ada/ada_version.h */ +/** + * @file ada_version.h + * @brief Definitions for Ada's version number. + */ +#ifndef ADA_ADA_VERSION_H +#define ADA_ADA_VERSION_H + +#define ADA_VERSION "3.0.0" + +namespace ada { + +enum { + ADA_VERSION_MAJOR = 3, + ADA_VERSION_MINOR = 0, + ADA_VERSION_REVISION = 0, +}; + +} // namespace ada + +#endif // ADA_ADA_VERSION_H +/* end file include/ada/ada_version.h */ +/* begin file include/ada/implementation-inl.h */ +/** + * @file implementation-inl.h + */ +#ifndef ADA_IMPLEMENTATION_INL_H +#define ADA_IMPLEMENTATION_INL_H + +#include +#include + +namespace ada { + +template +ada_warn_unused tl::expected, errors> +parse_url_pattern(std::variant input, + const std::string_view *base_url, + const url_pattern_options *options) { + return parser::parse_url_pattern_impl(std::move(input), + base_url, options); +} + +} // namespace ada + +#endif // ADA_IMPLEMENTATION_INL_H +/* end file include/ada/implementation-inl.h */ + +#endif // ADA_H +/* end file include/ada.h */ diff --git a/common/jsi/JsiPromise.cpp b/common/jsi/JsiPromise.cpp deleted file mode 100644 index 2043ac92a8..0000000000 --- a/common/jsi/JsiPromise.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "JsiPromise.h" - -namespace rnexecutorch { - -using namespace facebook; - -jsi::Value PromiseVendor::createPromise( - const std::function)> &function) { - if (runtime_ == nullptr) { - throw std::runtime_error("Runtime was null!"); - } - - auto &runtime = *runtime_; - auto callInvoker = callInvoker_; - - // get Promise constructor - auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise"); - - // create a "run" function (first Promise arg) - auto runPromise = jsi::Function::createFromHostFunction( - runtime, jsi::PropNameID::forUtf8(runtime, "runPromise"), 2, - [callInvoker, - function](jsi::Runtime &runtime, const jsi::Value &thisValue, - const jsi::Value *arguments, size_t count) -> jsi::Value { - auto resolveLocal = arguments[0].asObject(runtime).asFunction(runtime); - auto resolve = std::make_shared(std::move(resolveLocal)); - auto rejectLocal = arguments[1].asObject(runtime).asFunction(runtime); - auto reject = std::make_shared(std::move(rejectLocal)); - - auto resolveWrapper = - [resolve, &runtime, callInvoker]( - const std::function &resolver) - -> void { - callInvoker->invokeAsync([resolve, &runtime, resolver]() -> void { - auto valueShared = std::make_shared(resolver(runtime)); - - resolve->call(runtime, *valueShared); - }); - }; - - auto rejectWrapper = [reject, &runtime, callInvoker]( - const std::string &errorMessage) -> void { - auto error = jsi::JSError(runtime, errorMessage); - auto errorShared = std::make_shared(error); - callInvoker->invokeAsync([reject, &runtime, errorShared]() -> void { - reject->call(runtime, errorShared->value()); - }); - }; - - auto promise = std::make_shared(resolveWrapper, rejectWrapper); - function(promise); - - return jsi::Value::undefined(); - }); - - // return new Promise((resolve, reject) => ...) - return promiseCtor.callAsConstructor(runtime, runPromise); -} - -} // namespace rnexecutorch \ No newline at end of file diff --git a/common/jsi/JsiPromise.h b/common/jsi/JsiPromise.h deleted file mode 100644 index cc04c174af..0000000000 --- a/common/jsi/JsiPromise.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace rnexecutorch { - -using namespace facebook; - -class Promise { -public: - Promise(std::function)> - resolve, - std::function reject) - : resolve_(std::move(resolve)), reject_(std::move(reject)) {} - - void resolve(const std::function &resolver) { - resolve_(std::forward>( - resolver)); - } - - void reject(const std::string &errorMessage) { reject_(errorMessage); } - -private: - std::function)> resolve_; - std::function reject_; -}; - -class PromiseVendor { -public: - PromiseVendor(jsi::Runtime *runtime, - const std::shared_ptr &callInvoker) - : runtime_(runtime), callInvoker_(callInvoker) {} - - jsi::Value - createPromise(const std::function)> &function); - -private: - jsi::Runtime *runtime_; - std::shared_ptr callInvoker_; -}; - -} // namespace rnexecutorch \ No newline at end of file diff --git a/common/Log.h b/common/rnexecutorch/Log.cpp similarity index 78% rename from common/Log.h rename to common/rnexecutorch/Log.cpp index d72fae373d..1deaadcee9 100644 --- a/common/Log.h +++ b/common/rnexecutorch/Log.cpp @@ -1,7 +1,7 @@ -#pragma once +#include "Log.h" #include -#include +#include #ifdef __ANDROID__ #include @@ -12,23 +12,20 @@ namespace rnexecutorch { -enum class LOG_LEVEL { INFO, ERROR, DEBUG }; - #ifdef __ANDROID__ android_LogPriority androidLogLevel(LOG_LEVEL logLevel) { switch (logLevel) { - case LOG_LEVEL::INFO: + case LOG_LEVEL::Info: default: return ANDROID_LOG_INFO; - case LOG_LEVEL::ERROR: + case LOG_LEVEL::Error: return ANDROID_LOG_ERROR; - case LOG_LEVEL::DEBUG: + case LOG_LEVEL::Debug: return ANDROID_LOG_DEBUG; } } #endif -// const char* instead of const std::string& as va_start doesn't take references void log(LOG_LEVEL logLevel, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -52,14 +49,14 @@ void log(LOG_LEVEL logLevel, const char *fmt, ...) { #ifdef __APPLE__ switch (logLevel) { - case LOG_LEVEL::INFO: + case LOG_LEVEL::Info: default: os_log_info(OS_LOG_DEFAULT, "%s", buf); break; - case LOG_LEVEL::ERROR: + case LOG_LEVEL::Error: os_log_error(OS_LOG_DEFAULT, "%s", buf); break; - case LOG_LEVEL::DEBUG: + case LOG_LEVEL::Debug: os_log_debug(OS_LOG_DEFAULT, "%s", buf); break; } @@ -68,4 +65,4 @@ void log(LOG_LEVEL logLevel, const char *fmt, ...) { va_end(args); } -} // namespace rnexecutorch +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/Log.h b/common/rnexecutorch/Log.h new file mode 100644 index 0000000000..0072271d7f --- /dev/null +++ b/common/rnexecutorch/Log.h @@ -0,0 +1,10 @@ +#pragma once + +namespace rnexecutorch { + +enum class LOG_LEVEL { Info, Error, Debug }; + +// const char* instead of const std::string& as va_start doesn't take references +void log(LOG_LEVEL logLevel, const char *fmt, ...); + +} // namespace rnexecutorch diff --git a/common/rnexecutorch/RnExecutorchInstaller.cpp b/common/rnexecutorch/RnExecutorchInstaller.cpp new file mode 100644 index 0000000000..bdfdab231a --- /dev/null +++ b/common/rnexecutorch/RnExecutorchInstaller.cpp @@ -0,0 +1,29 @@ +#include "RnExecutorchInstaller.h" + +#include +#include +#include + +namespace rnexecutorch { + +// This function fetches data from a url address. It is implemented in +// Kotlin/ObjectiveC++ and then bound to this variable. It's done to not handle +// SSL intricacies manually, as it is done automagically in ObjC++/Kotlin. +FetchUrlFunc_t fetchUrlFunc; + +void RnExecutorchInstaller::injectJSIBindings( + jsi::Runtime *jsiRuntime, std::shared_ptr jsCallInvoker, + FetchUrlFunc_t fetchDataFromUrl) { + fetchUrlFunc = fetchDataFromUrl; + + jsiRuntime->global().setProperty( + *jsiRuntime, "loadStyleTransfer", + RnExecutorchInstaller::loadModel(jsiRuntime, jsCallInvoker, + "loadStyleTransfer")); + + jsiRuntime->global().setProperty( + *jsiRuntime, "loadImageSegmentation", + RnExecutorchInstaller::loadModel( + jsiRuntime, jsCallInvoker, "loadImageSegmentation")); +} +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/RnExecutorchInstaller.h b/common/rnexecutorch/RnExecutorchInstaller.h new file mode 100644 index 0000000000..3bb6fcf019 --- /dev/null +++ b/common/rnexecutorch/RnExecutorchInstaller.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include + +namespace rnexecutorch { + +using FetchUrlFunc_t = std::function(std::string)>; +extern FetchUrlFunc_t fetchUrlFunc; + +using namespace facebook; + +class RnExecutorchInstaller { +public: + static void + injectJSIBindings(jsi::Runtime *jsiRuntime, + std::shared_ptr jsCallInvoker, + FetchUrlFunc_t fetchDataFromUrl); + +private: + template + static jsi::Function + loadModel(jsi::Runtime *jsiRuntime, + std::shared_ptr jsCallInvoker, + const std::string &loadFunctionName) { + + return jsi::Function::createFromHostFunction( + *jsiRuntime, jsi::PropNameID::forAscii(*jsiRuntime, loadFunctionName), + 0, + [jsCallInvoker](jsi::Runtime &runtime, const jsi::Value &thisValue, + const jsi::Value *args, size_t count) -> jsi::Value { + assert(count == 1); + try { + auto source = + jsiconversion::getValue(args[0], runtime); + + auto modelImplementationPtr = + std::make_shared(source, jsCallInvoker); + auto modelHostObject = std::make_shared>( + modelImplementationPtr, jsCallInvoker); + + return jsi::Object::createFromHostObject(runtime, modelHostObject); + } catch (const std::runtime_error &e) { + // This catch should be merged with the next one + // (std::runtime_error inherits from std::exception) HOWEVER react + // native has broken RTTI which breaks proper exception type + // checking. Remove when the following change is present in our + // version: + // https://github.com/facebook/react-native/commit/3132cc88dd46f95898a756456bebeeb6c248f20e + throw jsi::JSError(runtime, e.what()); + return jsi::Value(); + } catch (const std::exception &e) { + throw jsi::JSError(runtime, e.what()); + return jsi::Value(); + } catch (...) { + throw jsi::JSError(runtime, "Unknown error"); + return jsi::Value(); + } + }); + } +}; + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/data_processing/FileUtils.h b/common/rnexecutorch/data_processing/FileUtils.h new file mode 100644 index 0000000000..98035b07b9 --- /dev/null +++ b/common/rnexecutorch/data_processing/FileUtils.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace rnexecutorch::fileutils { + +inline std::string getTimeID() { + return std::to_string(std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count()); +} + +} // namespace rnexecutorch::fileutils diff --git a/common/rnexecutorch/data_processing/ImageProcessing.cpp b/common/rnexecutorch/data_processing/ImageProcessing.cpp new file mode 100644 index 0000000000..ba192860b7 --- /dev/null +++ b/common/rnexecutorch/data_processing/ImageProcessing.cpp @@ -0,0 +1,131 @@ +#include "ImageProcessing.h" + +#include +#include + +#include + +#include +#include +#include +#include + +namespace rnexecutorch { +// This is defined in RnExecutorchInstaller.cpp. This function fetches data +// from a url address. It is implemented in Kotlin/ObjectiveC++ and then bound +// to this variable. It's done to not handle SSL intricacies manually, as it is +// done automagically in ObjC++/Kotlin. +extern FetchUrlFunc_t fetchUrlFunc; +namespace imageprocessing { +std::vector colorMatToVector(const cv::Mat &mat) { + return colorMatToVector(mat, cv::Scalar(0.0, 0.0, 0.0), + cv::Scalar(1.0, 1.0, 1.0)); +} + +std::vector colorMatToVector(const cv::Mat &mat, cv::Scalar mean, + cv::Scalar variance) { + int pixelCount = mat.cols * mat.rows; + std::vector v(pixelCount * 3); + + for (int i = 0; i < pixelCount; i++) { + int row = i / mat.cols; + int col = i % mat.cols; + cv::Vec3b pixel = mat.at(row, col); + v[0 * pixelCount + i] = + (pixel[0] - mean[0] * 255.0) / (variance[0] * 255.0); + v[1 * pixelCount + i] = + (pixel[1] - mean[1] * 255.0) / (variance[1] * 255.0); + v[2 * pixelCount + i] = + (pixel[2] - mean[2] * 255.0) / (variance[2] * 255.0); + } + + return v; +} + +cv::Mat bufferToColorMat(const std::span &buffer, + cv::Size matSize) { + cv::Mat mat(matSize, CV_8UC3); + + int pixelCount = matSize.width * matSize.height; + for (int i = 0; i < pixelCount; i++) { + int row = i / matSize.width; + int col = i % matSize.width; + + float r = buffer[0 * pixelCount + i]; + float g = buffer[1 * pixelCount + i]; + float b = buffer[2 * pixelCount + i]; + + cv::Vec3b color(static_cast(b * 255), static_cast(g * 255), + static_cast(r * 255)); + mat.at(row, col) = color; + } + + return mat; +} + +std::string saveToTempFile(const cv::Mat &image) { + std::string filename = "rn_executorch_" + fileutils::getTimeID() + ".png"; + + std::filesystem::path tempDir = std::filesystem::temp_directory_path(); + std::filesystem::path filePath = tempDir / filename; + + if (!cv::imwrite(filePath.string(), image)) { + throw std::runtime_error("Failed to save the image: " + filePath.string()); + } + + return "file://" + filePath.string(); +} + +cv::Mat readImage(const std::string &imageURI) { + cv::Mat image; + + if (imageURI.starts_with("data")) { + // base64 + std::stringstream uriStream(imageURI); + std::string stringData; + std::size_t segmentIndex{0}; + while (std::getline(uriStream, stringData, ',')) { + if (segmentIndex == 1) + break; + ++segmentIndex; + } + if (segmentIndex != 1) { + throw std::runtime_error("Read image error: invalid base64 URI"); + } + auto data = base64_decode(stringData); + cv::Mat encodedData(1, data.size(), CV_8UC1, (void *)data.data()); + image = cv::imdecode(encodedData, cv::IMREAD_COLOR); + } else if (imageURI.starts_with("file")) { + // local file + auto url = ada::parse(imageURI); + image = cv::imread(std::string{url->get_pathname()}, cv::IMREAD_COLOR); + } else if (imageURI.starts_with("http")) { + // remote file + std::vector imageData = fetchUrlFunc(imageURI); + image = cv::imdecode( + cv::Mat(1, imageData.size(), CV_8UC1, (void *)imageData.data()), + cv::IMREAD_COLOR); + } else { + throw std::runtime_error("Read image error: unknown protocol"); + } + + if (image.empty()) { + throw std::runtime_error("Read image error: invalid argument"); + } + + return image; +} + +TensorPtr getTensorFromMatrix(const std::vector &sizes, + const cv::Mat &matrix) { + std::vector inputVector = colorMatToVector(matrix); + return executorch::extension::make_tensor_ptr(sizes, inputVector); +} + +cv::Mat getMatrixFromTensor(cv::Size size, const Tensor &tensor) { + auto resultData = static_cast(tensor.const_data_ptr()); + return bufferToColorMat(std::span(resultData, tensor.numel()), + size); +} +} // namespace imageprocessing +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/data_processing/ImageProcessing.h b/common/rnexecutorch/data_processing/ImageProcessing.h new file mode 100644 index 0000000000..7e2a59e29d --- /dev/null +++ b/common/rnexecutorch/data_processing/ImageProcessing.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace rnexecutorch::imageprocessing { +using executorch::aten::Tensor; +using executorch::extension::TensorPtr; + +/// @brief Convert a OpenCV matrix to channel-first vector representation +std::vector colorMatToVector(const cv::Mat &mat, cv::Scalar mean, + cv::Scalar variance); +/// @brief Convert a OpenCV matrix to channel-first vector representation +std::vector colorMatToVector(const cv::Mat &mat); +/// @brief Convert a channel-first representation of an RGB image to OpenCV +/// matrix +cv::Mat bufferToColorMat(const std::span &buffer, + cv::Size matSize); +std::string saveToTempFile(const cv::Mat &image); +cv::Mat readImage(const std::string &imageURI); +TensorPtr getTensorFromMatrix(const std::vector &sizes, + const cv::Mat &mat); +cv::Mat getMatrixFromTensor(cv::Size size, const Tensor &tensor); + +} // namespace rnexecutorch::imageprocessing \ No newline at end of file diff --git a/common/rnexecutorch/data_processing/Numerical.cpp b/common/rnexecutorch/data_processing/Numerical.cpp new file mode 100644 index 0000000000..12920e7008 --- /dev/null +++ b/common/rnexecutorch/data_processing/Numerical.cpp @@ -0,0 +1,18 @@ +#include "Numerical.h" + +#include +#include + +namespace rnexecutorch::numerical { +void softmax(std::vector &v) { + float max = *std::max_element(v.begin(), v.end()); + + for (float &x : v) { + x = std::exp(x - max); + } + float sum = std::accumulate(v.begin(), v.end(), 0.f); + for (float &x : v) { + x /= sum; + } +} +} // namespace rnexecutorch::numerical \ No newline at end of file diff --git a/common/rnexecutorch/data_processing/Numerical.h b/common/rnexecutorch/data_processing/Numerical.h new file mode 100644 index 0000000000..88f252e59c --- /dev/null +++ b/common/rnexecutorch/data_processing/Numerical.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +namespace rnexecutorch::numerical { +void softmax(std::vector &v); +} \ No newline at end of file diff --git a/common/rnexecutorch/data_processing/base64.cpp b/common/rnexecutorch/data_processing/base64.cpp new file mode 100644 index 0000000000..a79bee9b8f --- /dev/null +++ b/common/rnexecutorch/data_processing/base64.cpp @@ -0,0 +1,110 @@ +#include "base64.h" +#include + +static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +static inline bool is_base64(BYTE c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +std::string base64_encode(BYTE const *buf, unsigned int bufLen) { + std::string ret; + int i = 0; + int j = 0; + BYTE char_array_3[3]; + BYTE char_array_4[4]; + + while (bufLen--) { + char_array_3[i++] = *(buf++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = + ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = + ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; (i < 4); i++) { + ret += base64_chars[char_array_4[i]]; + } + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + char_array_3[j] = '\0'; + } + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = + ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = + ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) { + ret += base64_chars[char_array_4[j]]; + } + + while ((i++ < 3)) { + ret += '='; + } + } + + return ret; +} + +std::vector base64_decode(std::string const &encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + BYTE char_array_4[4], char_array_3[3]; + std::vector ret; + + while (in_len-- && (encoded_string[in_] != '=') && + is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; + in_++; + if (i == 4) { + for (i = 0; i < 4; i++) { + char_array_4[i] = base64_chars.find(char_array_4[i]); + } + + char_array_3[0] = + (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = + ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) { + ret.push_back(char_array_3[i]); + } + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + char_array_4[j] = 0; + } + + for (j = 0; j < 4; j++) { + char_array_4[j] = base64_chars.find(char_array_4[j]); + } + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = + ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) { + ret.push_back(char_array_3[j]); + } + } + + return ret; +} \ No newline at end of file diff --git a/common/rnexecutorch/data_processing/base64.h b/common/rnexecutorch/data_processing/base64.h new file mode 100644 index 0000000000..5ebaaa84f9 --- /dev/null +++ b/common/rnexecutorch/data_processing/base64.h @@ -0,0 +1,46 @@ +/* + base64.cpp and base64.h + + base64 encoding and decoding with C++. + More information at + https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp + + Version: 2.rc.09 (release candidate) + + Copyright (C) 2004-2017, 2020-2022 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +// Modified version by LihO at https://stackoverflow.com/a/13935718/7470700 + +#ifndef _BASE64_H_ +#define _BASE64_H_ + +#include +#include +typedef unsigned char BYTE; + +std::string base64_encode(BYTE const *buf, unsigned int bufLen); +std::vector base64_decode(std::string const &); + +#endif \ No newline at end of file diff --git a/common/rnexecutorch/host_objects/JsiConversions.h b/common/rnexecutorch/host_objects/JsiConversions.h new file mode 100644 index 0000000000..e04e7fe54a --- /dev/null +++ b/common/rnexecutorch/host_objects/JsiConversions.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include + +#include + +namespace rnexecutorch::jsiconversion { + +using namespace facebook; + +// Conversion from jsi to C++ types -------------------------------------------- + +template T getValue(const jsi::Value &val, jsi::Runtime &runtime); + +template <> +inline double getValue(const jsi::Value &val, jsi::Runtime &runtime) { + return val.asNumber(); +} + +template <> +inline bool getValue(const jsi::Value &val, jsi::Runtime &runtime) { + return val.asBool(); +} + +template <> +inline std::string getValue(const jsi::Value &val, + jsi::Runtime &runtime) { + return val.getString(runtime).utf8(runtime); +} + +template <> +inline std::vector +getValue>(const jsi::Value &val, + jsi::Runtime &runtime) { + jsi::Array array = val.asObject(runtime).asArray(runtime); + size_t length = array.size(runtime); + std::vector result; + result.reserve(length); + + for (size_t i = 0; i < length; ++i) { + jsi::Value element = array.getValueAtIndex(runtime, i); + result.push_back(getValue(element, runtime)); + } + return result; +} + +// Set with heterogenerous look-up (adding std::less<> enables querying +// with std::string_view) +template <> +inline std::set> +getValue>>(const jsi::Value &val, + jsi::Runtime &runtime) { + // C++ set from JS array + + jsi::Array array = val.asObject(runtime).asArray(runtime); + size_t length = array.size(runtime); + std::set> result; + + for (size_t i = 0; i < length; ++i) { + jsi::Value element = array.getValueAtIndex(runtime, i); + result.insert(getValue(element, runtime)); + } + return result; +} + +// Conversion from C++ types to jsi -------------------------------------------- + +// Implementation functions might return any type, but in a promise we can only +// return jsi::Value or jsi::Object. For each type being returned +// we add a function here. + +// Identity function for the sake of completeness +inline jsi::Value getJsiValue(std::unique_ptr &&valuePtr, + jsi::Runtime &runtime) { + return std::move(*valuePtr); +} + +inline jsi::Value getJsiValue(const std::string &str, jsi::Runtime &runtime) { + return jsi::String::createFromAscii(runtime, str); +} + +template +constexpr std::size_t getArgumentCount(R (Model::*f)(Types...)) { + return sizeof...(Types); +} + +template +std::tuple fillTupleFromArgs(std::index_sequence, + const jsi::Value *args, + jsi::Runtime &runtime) { + return std::make_tuple(getValue(args[I], runtime)...); +} + +template +std::tuple createArgsTupleFromJsi(R (Model::*f)(Types...), + const jsi::Value *args, + jsi::Runtime &runtime) { + return fillTupleFromArgs(std::index_sequence_for{}, args, + runtime); +} + +} // namespace rnexecutorch::jsiconversion \ No newline at end of file diff --git a/common/rnexecutorch/host_objects/ModelHostObject.h b/common/rnexecutorch/host_objects/ModelHostObject.h new file mode 100644 index 0000000000..137654dc04 --- /dev/null +++ b/common/rnexecutorch/host_objects/ModelHostObject.h @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace rnexecutorch { + +template class ModelHostObject : public JsiHostObject { +public: + explicit ModelHostObject(const std::shared_ptr &model, + std::shared_ptr callInvoker) + : model(model), callInvoker(callInvoker) { + addFunctions(JSI_EXPORT_FUNCTION(ModelHostObject, forward)); + } + + JSI_HOST_FUNCTION(forward) { + auto promise = Promise::createPromise( + runtime, callInvoker, + [this, count, args, &runtime](std::shared_ptr promise) { + constexpr std::size_t forwardArgCount = + jsiconversion::getArgumentCount(&Model::forward); + if (forwardArgCount != count) { + char errorMessage[100]; + std::snprintf( + errorMessage, sizeof(errorMessage), + "Argument count mismatch, was expecting: %zu but got: %zu", + forwardArgCount, count); + promise->reject(errorMessage); + return; + } + + try { + auto argsConverted = jsiconversion::createArgsTupleFromJsi( + &Model::forward, args, runtime); + + // We need to dispatch a thread if we want the forward to be + // asynchronous. In this thread all accesses to jsi::Runtime need to + // be done via the callInvoker. + std::thread([this, promise, + argsConverted = std::move(argsConverted)]() { + try { + auto result = std::apply( + std::bind_front(&Model::forward, model), argsConverted); + + callInvoker->invokeSync([promise, + &result](jsi::Runtime &runtime) { + promise->resolve( + jsiconversion::getJsiValue(std::move(result), runtime)); + }); + } catch (const std::runtime_error &e) { + // This catch should be merged with the next two + // (std::runtime_error and jsi::JSError inherits from + // std::exception) HOWEVER react native has broken RTTI which + // breaks proper exception type checking. Remove when the + // following change is present in our version: + // https://github.com/facebook/react-native/commit/3132cc88dd46f95898a756456bebeeb6c248f20e + callInvoker->invokeAsync( + [&e, promise]() { promise->reject(e.what()); }); + return; + } catch (const jsi::JSError &e) { + callInvoker->invokeAsync( + [&e, promise]() { promise->reject(e.what()); }); + return; + } catch (const std::exception &e) { + callInvoker->invokeAsync( + [&e, promise]() { promise->reject(e.what()); }); + return; + } catch (...) { + callInvoker->invokeAsync( + [promise]() { promise->reject("Unknown error"); }); + return; + } + }).detach(); + } catch (...) { + promise->reject( + "Couldn't parse JS arguments in native forward function"); + } + }); + + return promise; + } + +private: + std::shared_ptr model; + std::shared_ptr callInvoker; +}; + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/jsi/JsiHostObject.cpp b/common/rnexecutorch/jsi/JsiHostObject.cpp new file mode 100644 index 0000000000..d07434325c --- /dev/null +++ b/common/rnexecutorch/jsi/JsiHostObject.cpp @@ -0,0 +1,108 @@ +#include "JsiHostObject.h" + +// set this value to 1 in order to debug the construction/destruction +#define JSI_DEBUG_ALLOCATIONS 1 + +namespace rnexecutorch { + +#if JSI_DEBUG_ALLOCATIONS +int objCounter = 0; +std::vector objects; +#endif + +JsiHostObject::JsiHostObject() { + getters_ = std::make_unique>(); + functions_ = std::make_unique< + std::unordered_map>(); + setters_ = std::make_unique>(); + +#if JSI_DEBUG_ALLOCATIONS + objects.push_back(this); + objCounter++; +#endif +} + +JsiHostObject::~JsiHostObject() { +#if JSI_DEBUG_ALLOCATIONS + for (size_t i = 0; i < objects.size(); ++i) { + if (objects.at(i) == this) { + objects.erase(objects.begin() + i); + break; + } + } + objCounter--; +#endif +} + +std::vector JsiHostObject::getPropertyNames(jsi::Runtime &rt) { + std::vector propertyNames; + propertyNames.reserve(getters_->size() + functions_->size() + + setters_->size()); + + for (const auto &it : *getters_) { + propertyNames.push_back(jsi::PropNameID::forUtf8(rt, it.first)); + } + + for (const auto &it : *functions_) { + propertyNames.push_back(jsi::PropNameID::forAscii(rt, it.first)); + } + + for (const auto &it : *setters_) { + propertyNames.push_back(jsi::PropNameID::forAscii(rt, it.first)); + } + + return propertyNames; +} + +jsi::Value JsiHostObject::get(jsi::Runtime &runtime, + const jsi::PropNameID &name) { + auto nameAsString = name.utf8(runtime); + auto &hostFunctionCache = hostFunctionCache_.get(runtime); + + auto cachedFunction = hostFunctionCache.find(nameAsString); + if (cachedFunction != hostFunctionCache.end()) { + return cachedFunction->second.asFunction(runtime); + } + + auto getter = getters_->find(nameAsString); + if (getter != getters_->end()) { + auto dispatcher = std::bind(getter->second, this, std::placeholders::_1); + + return dispatcher(runtime); + } + + auto function = functions_->find(nameAsString); + if (function == functions_->end()) { + return jsi::Value::undefined(); + } + + auto dispatcher = + std::bind(function->second, reinterpret_cast(this), + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4); + + return hostFunctionCache + .emplace(nameAsString, jsi::Function::createFromHostFunction( + runtime, name, 0, dispatcher)) + .first->second.asFunction(runtime); +} + +void JsiHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &name, + const jsi::Value &value) { + auto nameAsString = name.utf8(runtime); + + auto setter = setters_->find(nameAsString); + + if (setter != setters_->end()) { + auto dispatcher = std::bind(setter->second, this, std::placeholders::_1, + std::placeholders::_2); + + return dispatcher(runtime, value); + } +} +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/jsi/JsiHostObject.h b/common/rnexecutorch/jsi/JsiHostObject.h new file mode 100644 index 0000000000..b744bb79cd --- /dev/null +++ b/common/rnexecutorch/jsi/JsiHostObject.h @@ -0,0 +1,87 @@ +#pragma once +// Adapted from https://github.com/software-mansion/react-native-audio-api + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define JSI_HOST_FUNCTION(NAME) \ + jsi::Value NAME(jsi::Runtime &runtime, const jsi::Value &thisValue, \ + const jsi::Value *args, size_t count) + +#define JSI_EXPORT_FUNCTION(CLASS, FUNCTION) \ + std::make_pair( \ + std::string(#FUNCTION), \ + static_cast( \ + &CLASS::FUNCTION)) + +#define JSI_PROPERTY_GETTER(name) jsi::Value name(jsi::Runtime &runtime) + +#define JSI_EXPORT_PROPERTY_GETTER(CLASS, FUNCTION) \ + std::make_pair(std::string(#FUNCTION), \ + static_cast( \ + &CLASS::FUNCTION)) + +#define JSI_PROPERTY_SETTER(name) \ + void name(jsi::Runtime &runtime, const jsi::Value &value) + +#define JSI_EXPORT_PROPERTY_SETTER(CLASS, FUNCTION) \ + std::make_pair(std::string(#FUNCTION), \ + static_cast(&CLASS::FUNCTION)) + +namespace rnexecutorch { + +using namespace facebook; + +class JsiHostObject : public jsi::HostObject { +public: + JsiHostObject(); + ~JsiHostObject() override; + + std::vector getPropertyNames(jsi::Runtime &rt) override; + + jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override; + + void set(jsi::Runtime &runtime, const jsi::PropNameID &name, + const jsi::Value &value) override; + + template void addGetters(Args... args) { + (getters_->insert(args), ...); + } + + template void addSetters(Args... args) { + (setters_->insert(args), ...); + } + + template void addFunctions(Args... args) { + (functions_->insert(args), ...); + } + +protected: + std::unique_ptr> + getters_; + + std::unique_ptr< + std::unordered_map> + functions_; + + std::unique_ptr> + setters_; + +private: + RuntimeAwareCache> hostFunctionCache_; +}; + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/jsi/OwningArrayBuffer.h b/common/rnexecutorch/jsi/OwningArrayBuffer.h new file mode 100644 index 0000000000..51e9b63e49 --- /dev/null +++ b/common/rnexecutorch/jsi/OwningArrayBuffer.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +namespace rnexecutorch { + +using namespace facebook; + +class OwningArrayBuffer : public jsi::MutableBuffer { +public: + OwningArrayBuffer(const size_t size) : size_(size) { + data_ = new uint8_t[size]; + } + ~OwningArrayBuffer() override { delete[] data_; } + + OwningArrayBuffer(const OwningArrayBuffer &) = delete; + OwningArrayBuffer(OwningArrayBuffer &&) = delete; + OwningArrayBuffer &operator=(const OwningArrayBuffer &) = delete; + OwningArrayBuffer &operator=(OwningArrayBuffer &&) = delete; + + [[nodiscard]] size_t size() const override { return size_; } + uint8_t *data() override { return data_; } + +private: + uint8_t *data_; + const size_t size_; +}; + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/jsi/Promise.cpp b/common/rnexecutorch/jsi/Promise.cpp new file mode 100644 index 0000000000..f08f26654b --- /dev/null +++ b/common/rnexecutorch/jsi/Promise.cpp @@ -0,0 +1,20 @@ +#include "Promise.h" + +namespace rnexecutorch { + +Promise::Promise(jsi::Runtime &runtime, + std::shared_ptr callInvoker, + jsi::Value resolver, jsi::Value rejecter) + : runtime(runtime), callInvoker(callInvoker), + _resolver(std::move(resolver)), _rejecter(std::move(rejecter)) {} + +void Promise::resolve(jsi::Value &&result) { + _resolver.asObject(runtime).asFunction(runtime).call(runtime, result); +} + +void Promise::reject(std::string message) { + jsi::JSError error(runtime, message); + _rejecter.asObject(runtime).asFunction(runtime).call(runtime, error.value()); +} + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/jsi/Promise.h b/common/rnexecutorch/jsi/Promise.h new file mode 100644 index 0000000000..4dba088915 --- /dev/null +++ b/common/rnexecutorch/jsi/Promise.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include + +#include +#include + +namespace rnexecutorch { + +using namespace facebook; + +class Promise; + +template +concept PromiseRunFn = + std::invocable> && + std::same_as>, void>; + +class Promise { +public: + Promise(jsi::Runtime &runtime, + std::shared_ptr callInvoker, jsi::Value resolver, + jsi::Value rejecter); + + Promise(const Promise &) = delete; + Promise &operator=(const Promise &) = delete; + + void resolve(jsi::Value &&result); + void reject(std::string error); + + /** + Creates a new promise and runs the supplied "run" function that takes this + promise. We use a template for the function type to not use std::function + and be able to bind a lambda. + */ + template + static jsi::Value + createPromise(jsi::Runtime &runtime, + std::shared_ptr callInvoker, Fn &&run) { + // Get Promise ctor from global + auto promiseCtor = + runtime.global().getPropertyAsFunction(runtime, "Promise"); + + auto promiseCallback = jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forUtf8(runtime, "PromiseCallback"), 2, + [run = std::move(run), + callInvoker](jsi::Runtime &runtime, const jsi::Value &thisValue, + const jsi::Value *arguments, size_t count) -> jsi::Value { + // Call function + auto promise = std::make_shared( + runtime, callInvoker, arguments[0].asObject(runtime), + arguments[1].asObject(runtime)); + run(promise); + + return jsi::Value::undefined(); + }); + + return promiseCtor.callAsConstructor(runtime, promiseCallback); + } + +private: + jsi::Runtime &runtime; + std::shared_ptr callInvoker; + jsi::Value _resolver; + jsi::Value _rejecter; +}; + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/jsi/RuntimeAwareCache.h b/common/rnexecutorch/jsi/RuntimeAwareCache.h new file mode 100644 index 0000000000..dc7c8d0ff5 --- /dev/null +++ b/common/rnexecutorch/jsi/RuntimeAwareCache.h @@ -0,0 +1,58 @@ +#pragma once +// Adapted from https://github.com/software-mansion/react-native-audio-api + +// Header in jsi/ need to be added like this. See comment in JsiHostObject.h. +#include + +#include +#include +#include +#include + +namespace rnexecutorch { + +using namespace facebook; + +/** + * Provides a way to keep data specific to a jsi::Runtime instance that gets + * cleaned up when that runtime is destroyed. This is necessary because JSI does + * not allow for its associated objects to be retained past the runtime + * lifetime. If an object (e.g. jsi::Values or jsi::Function instances) is kept + * after the runtime is torn down, its destructor (once it is destroyed + * eventually) will result in a crash (JSI objects keep a pointer to memory + * managed by the runtime, accessing that portion of the memory after runtime is + * deleted is the root cause of that crash). + */ +template +class RuntimeAwareCache : public RuntimeLifecycleListener { +public: + void onRuntimeDestroyed(jsi::Runtime *rt) override { + // A runtime has been destroyed, so destroy the related cache. + runtimeCaches_.erase(rt); + } + + ~RuntimeAwareCache() override { + for (auto &cache : runtimeCaches_) { + // remove all `onRuntimeDestroyed` listeners. + RuntimeLifecycleMonitor::removeListener(*cache.first, this); + } + } + + T &get(jsi::Runtime &rt) { + if (runtimeCaches_.count(&rt) == 0) { + // This is the first time this Runtime has been accessed. + // We set up a `onRuntimeDestroyed` listener for it and + // initialize the cache map. + RuntimeLifecycleMonitor::addListener(rt, this); + + T cache; + runtimeCaches_.emplace(&rt, std::move(cache)); + } + return runtimeCaches_.at(&rt); + } + +private: + std::unordered_map runtimeCaches_; +}; + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/jsi/RuntimeLifecycleMonitor.cpp b/common/rnexecutorch/jsi/RuntimeLifecycleMonitor.cpp new file mode 100644 index 0000000000..a0d5465caf --- /dev/null +++ b/common/rnexecutorch/jsi/RuntimeLifecycleMonitor.cpp @@ -0,0 +1,53 @@ +#include "RuntimeLifecycleMonitor.h" + +namespace rnexecutorch { + +static std::unordered_map> + listeners; + +struct RuntimeLifecycleMonitorObject : public jsi::HostObject { + jsi::Runtime *rt_; + explicit RuntimeLifecycleMonitorObject(jsi::Runtime *rt) : rt_(rt) {} + ~RuntimeLifecycleMonitorObject() override { + auto listenersSet = listeners.find(rt_); + if (listenersSet != listeners.end()) { + for (auto listener : listenersSet->second) { + listener->onRuntimeDestroyed(rt_); + } + listeners.erase(listenersSet); + } + } +}; + +void RuntimeLifecycleMonitor::addListener(jsi::Runtime &rt, + RuntimeLifecycleListener *listener) { + auto listenersSet = listeners.find(&rt); + if (listenersSet == listeners.end()) { + // We install a global host object in the provided runtime, this way we can + // use that host object destructor to get notified when the runtime is being + // terminated. We use a unique name for the object as it gets saved with the + // runtime's global object. + rt.global().setProperty( + rt, "__rnaudioapi_runtime_lifecycle_monitor", + jsi::Object::createFromHostObject( + rt, std::make_shared(&rt))); + std::unordered_set newSet; + newSet.insert(listener); + listeners.emplace(&rt, std::move(newSet)); + } else { + listenersSet->second.insert(listener); + } +} + +void RuntimeLifecycleMonitor::removeListener( + jsi::Runtime &rt, RuntimeLifecycleListener *listener) { + auto listenersSet = listeners.find(&rt); + if (listenersSet == listeners.end()) { + // nothing to do here + } else { + listenersSet->second.erase(listener); + } +} + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/jsi/RuntimeLifecycleMonitor.h b/common/rnexecutorch/jsi/RuntimeLifecycleMonitor.h new file mode 100644 index 0000000000..7d0e88bbb6 --- /dev/null +++ b/common/rnexecutorch/jsi/RuntimeLifecycleMonitor.h @@ -0,0 +1,35 @@ +#pragma once +// Adapted from https://github.com/software-mansion/react-native-audio-api + +#include +#include +#include +#include +#include + +namespace rnexecutorch { + +using namespace facebook; + +/** + * Listener interface that allows for getting notified when a jsi::Runtime + * instance is destroyed. + */ +struct RuntimeLifecycleListener { + virtual ~RuntimeLifecycleListener() = default; + virtual void onRuntimeDestroyed(jsi::Runtime *) = 0; +}; + +/** + * This class provides an API via static methods for registering and + * unregistering runtime lifecycle listeners. The listeners can be used to + * cleanup any data that references a given jsi::Runtime instance before it gets + * destroyed. + */ +struct RuntimeLifecycleMonitor { + static void addListener(jsi::Runtime &rt, RuntimeLifecycleListener *listener); + static void removeListener(jsi::Runtime &rt, + RuntimeLifecycleListener *listener); +}; + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/models/BaseModel.cpp b/common/rnexecutorch/models/BaseModel.cpp new file mode 100644 index 0000000000..bb9073640f --- /dev/null +++ b/common/rnexecutorch/models/BaseModel.cpp @@ -0,0 +1,43 @@ +#include "BaseModel.h" + +#include + +namespace rnexecutorch { + +using namespace facebook; +using ::executorch::extension::Module; +using ::executorch::runtime::Error; + +BaseModel::BaseModel(const std::string &modelSource, + std::shared_ptr callInvoker) + : module(std::make_unique( + modelSource, Module::LoadMode::MmapUseMlockIgnoreErrors)), + callInvoker(callInvoker) { + Error loadError = module->load(); + if (loadError != Error::Ok) { + throw std::runtime_error("Couldn't load the model, error: " + + std::to_string(static_cast(loadError))); + } +} + +std::vector> BaseModel::getInputShape() { + auto method_meta = module->method_meta("forward"); + + if (!method_meta.ok()) { + throw std::runtime_error("Failed to load forward"); + } + std::vector> output; + std::size_t numInputs = method_meta->num_inputs(); + output.reserve(numInputs); + for (std::size_t input = 0; input < numInputs; ++input) { + auto input_meta = method_meta->input_tensor_meta(input); + if (!input_meta.ok()) { + throw std::runtime_error("Failed to load forward input"); + } + auto shape = input_meta->sizes(); + output.emplace_back(std::vector(shape.begin(), shape.end())); + } + return output; +} + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/models/BaseModel.h b/common/rnexecutorch/models/BaseModel.h new file mode 100644 index 0000000000..492ae8c044 --- /dev/null +++ b/common/rnexecutorch/models/BaseModel.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include +#include +#include + +namespace rnexecutorch { +using namespace facebook; + +class BaseModel { +public: + BaseModel(const std::string &modelSource, + std::shared_ptr callInvoker); + std::vector> getInputShape(); + +protected: + std::unique_ptr module; + // If possible, models should not use the JS runtime to keep JSI internals + // away from logic, however, sometimes this would incur too big of a penalty + // (unnecessary copies instead of working on JS memory). In this case + // CallInvoker can be used to get jsi::Runtime, and use it in a safe manner. + std::shared_ptr callInvoker; +}; +} // namespace rnexecutorch \ No newline at end of file diff --git a/ios/RnExecutorch/models/image_segmentation/Constants.mm b/common/rnexecutorch/models/image_segmentation/Constants.h similarity index 62% rename from ios/RnExecutorch/models/image_segmentation/Constants.mm rename to common/rnexecutorch/models/image_segmentation/Constants.h index f28693c75f..a6d69e1c29 100644 --- a/ios/RnExecutorch/models/image_segmentation/Constants.mm +++ b/common/rnexecutorch/models/image_segmentation/Constants.h @@ -1,8 +1,13 @@ -#import "Constants.h" +#pragma once -const std::vector deeplabv3_resnet50_labels = { +#include +#include + +namespace rnexecutorch { +inline constexpr std::array deeplabv3_resnet50_labels = { "BACKGROUND", "AEROPLANE", "BICYCLE", "BIRD", "BOAT", "BOTTLE", "BUS", "CAR", "CAT", "CHAIR", "COW", "DININGTABLE", "DOG", "HORSE", "MOTORBIKE", "PERSON", "POTTEDPLANT", "SHEEP", "SOFA", "TRAIN", "TVMONITOR"}; +} \ No newline at end of file diff --git a/common/rnexecutorch/models/image_segmentation/ImageSegmentation.cpp b/common/rnexecutorch/models/image_segmentation/ImageSegmentation.cpp new file mode 100644 index 0000000000..f0ed9dd6b5 --- /dev/null +++ b/common/rnexecutorch/models/image_segmentation/ImageSegmentation.cpp @@ -0,0 +1,168 @@ +#include "ImageSegmentation.h" + +#include + +#include +#include +#include +#include + +namespace rnexecutorch { + +ImageSegmentation::ImageSegmentation( + const std::string &modelSource, + std::shared_ptr callInvoker) + : BaseModel(modelSource, callInvoker) { + + std::vector modelInputShape = getInputShape()[0]; + modelImageSize = cv::Size(modelInputShape[modelInputShape.size() - 1], + modelInputShape[modelInputShape.size() - 2]); + numModelPixels = modelImageSize.area(); +} + +std::unique_ptr +ImageSegmentation::forward(std::string imageSource, + std::set> classesOfInterest, + bool resize) { + auto [inputTensor, originalSize] = preprocess(imageSource); + + auto forwardResult = module->forward(inputTensor); + if (!forwardResult.ok()) { + throw std::runtime_error( + "Failed to forward, error: " + + std::to_string(static_cast(forwardResult.error()))); + } + + return postprocess(forwardResult->at(0).toTensor(), originalSize, + classesOfInterest, resize); +} + +std::pair +ImageSegmentation::preprocess(const std::string &imageSource) { + cv::Mat input = imageprocessing::readImage(imageSource); + cv::Size inputSize = input.size(); + + cv::resize(input, input, modelImageSize); + + std::vector inputVector = imageprocessing::colorMatToVector(input); + return { + executorch::extension::make_tensor_ptr(getInputShape()[0], inputVector), + inputSize}; +} + +std::unique_ptr ImageSegmentation::postprocess( + const Tensor &tensor, cv::Size originalSize, + std::set> classesOfInterest, bool resize) { + + auto dataPtr = static_cast(tensor.const_data_ptr()); + auto resultData = std::span(dataPtr, tensor.numel()); + + // We copy the ET-owned data to jsi array buffers that can be directly + // returned to JS + std::vector> resultClasses; + resultClasses.reserve(numClasses); + for (std::size_t cl = 0; cl < numClasses; ++cl) { + auto classBuffer = + std::make_shared(numModelPixels * sizeof(float)); + resultClasses.emplace_back(classBuffer); + std::memcpy(classBuffer->data(), &resultData[cl * numModelPixels], + numModelPixels * sizeof(float)); + } + + // Apply softmax per each pixel across all classes + for (std::size_t pixel = 0; pixel < numModelPixels; ++pixel) { + std::vector classValues(numClasses); + for (std::size_t cl = 0; cl < numClasses; ++cl) { + classValues[cl] = + reinterpret_cast(resultClasses[cl]->data())[pixel]; + } + numerical::softmax(classValues); + for (std::size_t cl = 0; cl < numClasses; ++cl) { + reinterpret_cast(resultClasses[cl]->data())[pixel] = + classValues[cl]; + } + } + + // Calculate the maximum class for each pixel + auto argmax = + std::make_shared(numModelPixels * sizeof(int32_t)); + for (std::size_t pixel = 0; pixel < numModelPixels; ++pixel) { + float max = reinterpret_cast(resultClasses[0]->data())[pixel]; + int maxInd = 0; + for (int cl = 1; cl < numClasses; ++cl) { + if (reinterpret_cast(resultClasses[cl]->data())[pixel] > max) { + maxInd = cl; + max = reinterpret_cast(resultClasses[cl]->data())[pixel]; + } + } + reinterpret_cast(argmax->data())[pixel] = maxInd; + } + + auto buffersToReturn = std::make_shared>>(); + for (std::size_t cl = 0; cl < numClasses; ++cl) { + if (classesOfInterest.contains(deeplabv3_resnet50_labels[cl])) { + (*buffersToReturn)[deeplabv3_resnet50_labels[cl]] = resultClasses[cl]; + } + } + + // Resize selected classes and argmax + if (resize) { + cv::Mat argmaxMat(modelImageSize, CV_32SC1, argmax->data()); + cv::resize(argmaxMat, argmaxMat, originalSize, 0, 0, + cv::InterpolationFlags::INTER_NEAREST); + argmax = std::make_shared(originalSize.area() * + sizeof(int32_t)); + std::memcpy(argmax->data(), argmaxMat.data, + originalSize.area() * sizeof(int32_t)); + + for (auto &[label, arrayBuffer] : *buffersToReturn) { + cv::Mat classMat(modelImageSize, CV_32FC1, arrayBuffer->data()); + cv::resize(classMat, classMat, originalSize); + arrayBuffer = std::make_shared(originalSize.area() * + sizeof(float)); + std::memcpy(arrayBuffer->data(), classMat.data, + originalSize.area() * sizeof(float)); + } + } + return populateDictionary(argmax, buffersToReturn); +} + +std::unique_ptr ImageSegmentation::populateDictionary( + std::shared_ptr argmax, + std::shared_ptr>> + classesToOutput) { + std::unique_ptr dictPtr; + + callInvoker->invokeSync( + [argmax, classesToOutput, &dictPtr](jsi::Runtime &runtime) { + dictPtr = std::make_unique(runtime); + auto argmaxArrayBuffer = jsi::ArrayBuffer(runtime, argmax); + + auto int32ArrayCtor = + runtime.global().getPropertyAsFunction(runtime, "Int32Array"); + auto int32Array = + int32ArrayCtor.callAsConstructor(runtime, argmaxArrayBuffer) + .getObject(runtime); + dictPtr->setProperty(runtime, "ARGMAX", int32Array); + + for (auto &[classLabel, owningBuffer] : *classesToOutput) { + auto classArrayBuffer = jsi::ArrayBuffer(runtime, owningBuffer); + + auto float32ArrayCtor = + runtime.global().getPropertyAsFunction(runtime, "Float32Array"); + auto float32Array = + float32ArrayCtor.callAsConstructor(runtime, classArrayBuffer) + .getObject(runtime); + + dictPtr->setProperty( + runtime, jsi::String::createFromAscii(runtime, classLabel.data()), + float32Array); + } + }); + + return dictPtr; +} + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/models/image_segmentation/ImageSegmentation.h b/common/rnexecutorch/models/image_segmentation/ImageSegmentation.h new file mode 100644 index 0000000000..ea116b56e6 --- /dev/null +++ b/common/rnexecutorch/models/image_segmentation/ImageSegmentation.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace rnexecutorch { +using namespace facebook; + +using executorch::aten::Tensor; +using executorch::extension::TensorPtr; + +class ImageSegmentation : public BaseModel { +public: + ImageSegmentation(const std::string &modelSource, + std::shared_ptr callInvoker); + std::unique_ptr + forward(std::string imageSource, + std::set> classesOfInterest, bool resize); + +private: + std::pair preprocess(const std::string &imageSource); + std::unique_ptr + postprocess(const Tensor &tensor, cv::Size originalSize, + std::set> classesOfInterest, + bool resize); + std::unique_ptr populateDictionary( + std::shared_ptr argmax, + std::shared_ptr>> + classesToOutput); + + static constexpr std::size_t numClasses{deeplabv3_resnet50_labels.size()}; + cv::Size modelImageSize; + std::size_t numModelPixels; +}; +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/models/style_transfer/StyleTransfer.cpp b/common/rnexecutorch/models/style_transfer/StyleTransfer.cpp new file mode 100644 index 0000000000..cda9f66a44 --- /dev/null +++ b/common/rnexecutorch/models/style_transfer/StyleTransfer.cpp @@ -0,0 +1,56 @@ +#include "StyleTransfer.h" + +#include +#include + +#include + +#include +#include + +namespace rnexecutorch { +using namespace facebook; +using executorch::extension::Module; +using executorch::extension::TensorPtr; +using executorch::runtime::Error; + +StyleTransfer::StyleTransfer(const std::string &modelSource, + std::shared_ptr callInvoker) + : BaseModel(modelSource, callInvoker) { + std::vector modelInputShape = getInputShape()[0]; + modelImageSize = cv::Size(modelInputShape[modelInputShape.size() - 1], + modelInputShape[modelInputShape.size() - 2]); +} + +std::pair +StyleTransfer::preprocess(const std::string &imageSource) { + cv::Mat image = imageprocessing::readImage(imageSource); + auto originalSize = image.size(); + cv::resize(image, image, modelImageSize); + + return {imageprocessing::getTensorFromMatrix(getInputShape()[0], image), + originalSize}; +} + +std::string StyleTransfer::postprocess(const Tensor &tensor, + cv::Size originalSize) { + cv::Mat mat = imageprocessing::getMatrixFromTensor(modelImageSize, tensor); + cv::resize(mat, mat, originalSize); + + return imageprocessing::saveToTempFile(mat); +} + +std::string StyleTransfer::forward(std::string imageSource) { + auto [tensor, originalSize] = preprocess(imageSource); + + auto forwardResult = module->forward(tensor); + if (!forwardResult.ok()) { + throw std::runtime_error( + "Failed to forward, error: " + + std::to_string(static_cast(forwardResult.error()))); + } + + return postprocess(forwardResult->at(0).toTensor(), originalSize); +} + +} // namespace rnexecutorch \ No newline at end of file diff --git a/common/rnexecutorch/models/style_transfer/StyleTransfer.h b/common/rnexecutorch/models/style_transfer/StyleTransfer.h new file mode 100644 index 0000000000..809cac804d --- /dev/null +++ b/common/rnexecutorch/models/style_transfer/StyleTransfer.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include + +namespace rnexecutorch { +using namespace facebook; +using executorch::aten::Tensor; +using executorch::extension::TensorPtr; + +class StyleTransfer : public BaseModel { +public: + StyleTransfer(const std::string &modelSource, + std::shared_ptr callInvoker); + std::string forward(std::string imageSource); + +private: + std::pair preprocess(const std::string &imageSource); + std::string postprocess(const Tensor &tensor, cv::Size originalSize); + + cv::Size modelImageSize{0, 0}; +}; +} // namespace rnexecutorch diff --git a/examples/computer-vision/ios/Podfile.lock b/examples/computer-vision/ios/Podfile.lock index 036a62c773..b11ac3d434 100644 --- a/examples/computer-vision/ios/Podfile.lock +++ b/examples/computer-vision/ios/Podfile.lock @@ -43,7 +43,7 @@ PODS: - hermes-engine (0.76.9): - hermes-engine/Pre-built (= 0.76.9) - hermes-engine/Pre-built (0.76.9) - - opencv-rne (0.1.0) + - opencv-rne (4.11.0) - RCT-Folly (2024.10.14.00): - boost - DoubleConversion @@ -1326,7 +1326,7 @@ PODS: - DoubleConversion - glog - hermes-engine - - opencv-rne (~> 0.1.0) + - opencv-rne (~> 4.11.0) - RCT-Folly (= 2024.10.14.00) - RCTRequired - RCTTypeSafety @@ -1343,6 +1343,7 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - sqlite3 - Yoga - react-native-image-picker (7.2.3): - DoubleConversion @@ -1857,6 +1858,9 @@ PODS: - ReactCommon/turbomodule/core - Yoga - SocketRocket (0.7.1) + - sqlite3 (3.49.1): + - sqlite3/common (= 3.49.1) + - sqlite3/common (3.49.1) - Yoga (0.0.0) DEPENDENCIES: @@ -1944,6 +1948,7 @@ SPEC REPOS: trunk: - opencv-rne - SocketRocket + - sqlite3 EXTERNAL SOURCES: boost: @@ -2117,7 +2122,7 @@ SPEC CHECKSUMS: fmt: 01b82d4ca6470831d1cc0852a1af644be019e8f6 glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a hermes-engine: 9e868dc7be781364296d6ee2f56d0c1a9ef0bb11 - opencv-rne: 63e933ae2373fc91351f9a348dc46c3f523c2d3f + opencv-rne: 2305807573b6e29c8c87e3416ab096d09047a7a0 RCT-Folly: ea9d9256ba7f9322ef911169a9f696e5857b9e17 RCTDeprecation: ebe712bb05077934b16c6bf25228bdec34b64f83 RCTRequired: ca91e5dd26b64f577b528044c962baf171c6b716 @@ -2181,6 +2186,7 @@ SPEC CHECKSUMS: RNReanimated: 2e5069649cbab2c946652d3b97589b2ae0526220 RNSVG: b889dc9c1948eeea0576a16cc405c91c37a12c19 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 + sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983 Yoga: feb4910aba9742cfedc059e2b2902e22ffe9954a PODFILE CHECKSUM: d2d76566c3147849493ab633854730a1f661227b diff --git a/examples/computer-vision/screens/ImageSegmentationScreen.tsx b/examples/computer-vision/screens/ImageSegmentationScreen.tsx index 3a43236b98..4ffbd1440b 100644 --- a/examples/computer-vision/screens/ImageSegmentationScreen.tsx +++ b/examples/computer-vision/screens/ImageSegmentationScreen.tsx @@ -3,7 +3,6 @@ import { BottomBar } from '../components/BottomBar'; import { getImage } from '../utils'; import { useImageSegmentation, - DeeplabLabel, DEEPLAB_V3_RESNET50, } from 'react-native-executorch'; import { @@ -80,16 +79,14 @@ export const ImageSegmentationScreen = ({ const runForward = async () => { if (imageUri) { try { - const output = await model.forward(imageUri); + const output = await model.forward(imageUri, [], false); pixels = new Uint8Array(width * height * 4); for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { for (let i = 0; i < 3; i++) { pixels[(x * height + y) * 4 + i] = - numberToColor[ - (output[DeeplabLabel.ARGMAX] || [])[x * height + y] - ][i]; + numberToColor[(output['ARGMAX'] || [])[x * height + y]][i]; } pixels[(x * height + y) * 4 + 3] = 255; } diff --git a/ios/RnExecutorch.xcodeproj/project.pbxproj b/ios/RnExecutorch.xcodeproj/project.pbxproj index f95bb5caa0..356c2ca03b 100644 --- a/ios/RnExecutorch.xcodeproj/project.pbxproj +++ b/ios/RnExecutorch.xcodeproj/project.pbxproj @@ -8,7 +8,10 @@ /* Begin PBXBuildFile section */ 55D6EA8C2D0987D2009BA408 /* ExecutorchLib.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D6EA8B2D0987D2009BA408 /* ExecutorchLib.xcframework */; }; - 8C53B8782D96BFCD0097900E /* JsiPromise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C53B8702D96BFCD0097900E /* JsiPromise.cpp */; }; + 8C9A9BD02DB0CE800027DD32 /* ImageSegmentation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C9A9BCA2DB0CE800027DD32 /* ImageSegmentation.cpp */; }; + 8C9A9BD12DB0CE800027DD32 /* RuntimeLifecycleMonitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C9A9BC72DB0CE800027DD32 /* RuntimeLifecycleMonitor.cpp */; }; + 8C9A9BD22DB0CE800027DD32 /* JsiHostObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C9A9BC22DB0CE800027DD32 /* JsiHostObject.cpp */; }; + 8C9A9BD32DB0CE800027DD32 /* JsiPromise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C9A9BC42DB0CE800027DD32 /* JsiPromise.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -26,10 +29,18 @@ /* Begin PBXFileReference section */ 550986892CEF541900FECBB8 /* libRnExecutorch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRnExecutorch.a; sourceTree = BUILT_PRODUCTS_DIR; }; 55D6EA8B2D0987D2009BA408 /* ExecutorchLib.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = ExecutorchLib.xcframework; sourceTree = ""; }; - 8C53B86F2D96BFCD0097900E /* JsiPromise.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JsiPromise.h; sourceTree = ""; }; - 8C53B8702D96BFCD0097900E /* JsiPromise.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JsiPromise.cpp; sourceTree = ""; }; - 8C53B8752D96BFCD0097900E /* RnExecutorchInstaller.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RnExecutorchInstaller.h; sourceTree = ""; }; - 8CB19AA72DA3D1A200EB6786 /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = ""; }; + 8C9A9BBF2DB0CE800027DD32 /* ModelHostObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ModelHostObject.h; sourceTree = ""; }; + 8C9A9BC12DB0CE800027DD32 /* JsiHostObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JsiHostObject.h; sourceTree = ""; }; + 8C9A9BC22DB0CE800027DD32 /* JsiHostObject.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JsiHostObject.cpp; sourceTree = ""; }; + 8C9A9BC32DB0CE800027DD32 /* JsiPromise.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JsiPromise.h; sourceTree = ""; }; + 8C9A9BC42DB0CE800027DD32 /* JsiPromise.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JsiPromise.cpp; sourceTree = ""; }; + 8C9A9BC52DB0CE800027DD32 /* RuntimeAwareCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RuntimeAwareCache.h; sourceTree = ""; }; + 8C9A9BC62DB0CE800027DD32 /* RuntimeLifecycleMonitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RuntimeLifecycleMonitor.h; sourceTree = ""; }; + 8C9A9BC72DB0CE800027DD32 /* RuntimeLifecycleMonitor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RuntimeLifecycleMonitor.cpp; sourceTree = ""; }; + 8C9A9BC92DB0CE800027DD32 /* ImageSegmentation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageSegmentation.h; sourceTree = ""; }; + 8C9A9BCA2DB0CE800027DD32 /* ImageSegmentation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ImageSegmentation.cpp; sourceTree = ""; }; + 8C9A9BCC2DB0CE800027DD32 /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = ""; }; + 8C9A9BCD2DB0CE800027DD32 /* RnExecutorchInstaller.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RnExecutorchInstaller.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */ @@ -76,7 +87,7 @@ 550986802CEF541900FECBB8 = { isa = PBXGroup; children = ( - 8C53B8762D96BFCD0097900E /* common */, + 8C9A9BCF2DB0CE800027DD32 /* common */, 5509868B2CEF541900FECBB8 /* RnExecutorch */, 55D6EA8A2D0987D2009BA408 /* Frameworks */, 5509868A2CEF541900FECBB8 /* Products */, @@ -99,21 +110,53 @@ name = Frameworks; sourceTree = ""; }; - 8C53B8712D96BFCD0097900E /* jsi */ = { + 8C9A9BC02DB0CE800027DD32 /* host_objects */ = { isa = PBXGroup; children = ( - 8C53B86F2D96BFCD0097900E /* JsiPromise.h */, - 8C53B8702D96BFCD0097900E /* JsiPromise.cpp */, + 8C9A9BBF2DB0CE800027DD32 /* ModelHostObject.h */, + ); + path = host_objects; + sourceTree = ""; + }; + 8C9A9BC82DB0CE800027DD32 /* jsi */ = { + isa = PBXGroup; + children = ( + 8C9A9BC12DB0CE800027DD32 /* JsiHostObject.h */, + 8C9A9BC22DB0CE800027DD32 /* JsiHostObject.cpp */, + 8C9A9BC32DB0CE800027DD32 /* JsiPromise.h */, + 8C9A9BC42DB0CE800027DD32 /* JsiPromise.cpp */, + 8C9A9BC52DB0CE800027DD32 /* RuntimeAwareCache.h */, + 8C9A9BC62DB0CE800027DD32 /* RuntimeLifecycleMonitor.h */, + 8C9A9BC72DB0CE800027DD32 /* RuntimeLifecycleMonitor.cpp */, ); path = jsi; sourceTree = ""; }; - 8C53B8762D96BFCD0097900E /* common */ = { + 8C9A9BCB2DB0CE800027DD32 /* modules */ = { + isa = PBXGroup; + children = ( + 8C9A9BC92DB0CE800027DD32 /* ImageSegmentation.h */, + 8C9A9BCA2DB0CE800027DD32 /* ImageSegmentation.cpp */, + ); + path = modules; + sourceTree = ""; + }; + 8C9A9BCE2DB0CE800027DD32 /* rnexecutorch */ = { + isa = PBXGroup; + children = ( + 8C9A9BC02DB0CE800027DD32 /* host_objects */, + 8C9A9BC82DB0CE800027DD32 /* jsi */, + 8C9A9BCB2DB0CE800027DD32 /* modules */, + 8C9A9BCC2DB0CE800027DD32 /* Log.h */, + 8C9A9BCD2DB0CE800027DD32 /* RnExecutorchInstaller.h */, + ); + path = rnexecutorch; + sourceTree = ""; + }; + 8C9A9BCF2DB0CE800027DD32 /* common */ = { isa = PBXGroup; children = ( - 8CB19AA72DA3D1A200EB6786 /* Log.h */, - 8C53B8712D96BFCD0097900E /* jsi */, - 8C53B8752D96BFCD0097900E /* RnExecutorchInstaller.h */, + 8C9A9BCE2DB0CE800027DD32 /* rnexecutorch */, ); name = common; path = ../common; @@ -181,7 +224,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8C53B8782D96BFCD0097900E /* JsiPromise.cpp in Sources */, + 8C9A9BD02DB0CE800027DD32 /* ImageSegmentation.cpp in Sources */, + 8C9A9BD12DB0CE800027DD32 /* RuntimeLifecycleMonitor.cpp in Sources */, + 8C9A9BD22DB0CE800027DD32 /* JsiHostObject.cpp in Sources */, + 8C9A9BD32DB0CE800027DD32 /* JsiPromise.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/RnExecutorch/ETInstaller.mm b/ios/RnExecutorch/ETInstaller.mm index b7a079c362..dcb40b29d8 100644 --- a/ios/RnExecutorch/ETInstaller.mm +++ b/ios/RnExecutorch/ETInstaller.mm @@ -4,7 +4,8 @@ #import #import -#include +#include +#include using namespace facebook::react; @@ -25,8 +26,23 @@ @implementation ETInstaller assert(jsiRuntime != nullptr); - rnexecutorch::RnExecutorchInstaller::injectJSIBindings(jsiRuntime, - jsCallInvoker); + auto fetchUrl = [](std::string url) { + @try { + NSString *nsUrlStr = + [NSString stringWithCString:url.c_str() + encoding:[NSString defaultCStringEncoding]]; + NSURL *nsUrl = [NSURL URLWithString:nsUrlStr]; + NSData *data = [NSData dataWithContentsOfURL:nsUrl]; + const std::byte *bytePtr = + reinterpret_cast(data.bytes); + int bufferLength = [data length]; + return std::vector(bytePtr, bytePtr + bufferLength); + } @catch (NSException *exception) { + throw std::runtime_error("Error fetching data from a url"); + } + }; + rnexecutorch::RnExecutorchInstaller::injectJSIBindings( + jsiRuntime, jsCallInvoker, fetchUrl); NSLog(@"Successfully installed JSI bindings for react-native-executorch!"); return @true; diff --git a/ios/RnExecutorch/ImageSegmentation.h b/ios/RnExecutorch/ImageSegmentation.h deleted file mode 100644 index 59ed56a45c..0000000000 --- a/ios/RnExecutorch/ImageSegmentation.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface ImageSegmentation : NSObject - -@end \ No newline at end of file diff --git a/ios/RnExecutorch/ImageSegmentation.mm b/ios/RnExecutorch/ImageSegmentation.mm deleted file mode 100644 index d64a73abc9..0000000000 --- a/ios/RnExecutorch/ImageSegmentation.mm +++ /dev/null @@ -1,60 +0,0 @@ -#import "ImageSegmentation.h" -#import "ImageProcessor.h" -#import "models/image_segmentation/ImageSegmentationModel.h" - -@implementation ImageSegmentation { - ImageSegmentationModel *model; -} - -RCT_EXPORT_MODULE() - -- (void)releaseResources { - model = nil; -} - -- (void)loadModule:(NSString *)modelSource - resolve:(RCTPromiseResolveBlock)resolve - reject:(RCTPromiseRejectBlock)reject { - model = [[ImageSegmentationModel alloc] init]; - - NSNumber *errorCode = [model loadModel:modelSource]; - if ([errorCode intValue] != 0) { - [self releaseResources]; - reject(@"init_module_error", - [NSString stringWithFormat:@"%ld", (long)[errorCode longValue]], - nil); - return; - } - - resolve(@0); -} - -- (void)forward:(NSString *)input - classesOfInterest:(NSArray *)classesOfInterest - resize:(BOOL)resize - resolve:(RCTPromiseResolveBlock)resolve - reject:(RCTPromiseRejectBlock)reject { - - @try { - cv::Mat image = [ImageProcessor readImage:input]; - NSDictionary *result = [model runModel:image - returnClasses:classesOfInterest - resize:resize]; - - resolve(result); - return; - } @catch (NSException *exception) { - NSLog(@"An exception occurred: %@, %@", exception.name, exception.reason); - reject(@"forward_error", - [NSString stringWithFormat:@"%@", exception.reason], nil); - return; - } -} - -- (std::shared_ptr)getTurboModule: - (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared( - params); -} - -@end diff --git a/ios/RnExecutorch/StyleTransfer.h b/ios/RnExecutorch/StyleTransfer.h deleted file mode 100644 index bd9d671fd3..0000000000 --- a/ios/RnExecutorch/StyleTransfer.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface StyleTransfer : NSObject - -@end diff --git a/ios/RnExecutorch/StyleTransfer.mm b/ios/RnExecutorch/StyleTransfer.mm deleted file mode 100644 index 9f7b1770f4..0000000000 --- a/ios/RnExecutorch/StyleTransfer.mm +++ /dev/null @@ -1,55 +0,0 @@ -#import "StyleTransfer.h" -#import "ImageProcessor.h" -#import "models/style_transfer/StyleTransferModel.h" - -@implementation StyleTransfer { - StyleTransferModel *model; -} - -RCT_EXPORT_MODULE() - -- (void)releaseResources { - model = nil; -} - -- (void)loadModule:(NSString *)modelSource - resolve:(RCTPromiseResolveBlock)resolve - reject:(RCTPromiseRejectBlock)reject { - model = [[StyleTransferModel alloc] init]; - - NSNumber *errorCode = [model loadModel:modelSource]; - if ([errorCode intValue] != 0) { - [self releaseResources]; - reject(@"init_module_error", - [NSString stringWithFormat:@"%ld", (long)[errorCode longValue]], - nil); - return; - } - - resolve(@0); -} - -- (void)forward:(NSString *)input - resolve:(RCTPromiseResolveBlock)resolve - reject:(RCTPromiseRejectBlock)reject { - @try { - cv::Mat image = [ImageProcessor readImage:input]; - cv::Mat resultImage = [model runModel:image]; - - NSString *tempFilePath = [ImageProcessor saveToTempFile:resultImage]; - resolve(tempFilePath); - return; - } @catch (NSException *exception) { - NSLog(@"An exception occurred: %@, %@", exception.name, exception.reason); - reject(@"forward_error", - [NSString stringWithFormat:@"%@", exception.reason], nil); - return; - } -} - -- (std::shared_ptr)getTurboModule: - (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); -} - -@end diff --git a/ios/RnExecutorch/models/classification/ClassificationModel.h b/ios/RnExecutorch/models/classification/ClassificationModel.h index 77c034b1fe..3df50a1e3c 100644 --- a/ios/RnExecutorch/models/classification/ClassificationModel.h +++ b/ios/RnExecutorch/models/classification/ClassificationModel.h @@ -1,4 +1,4 @@ -#import "BaseModel.h" +#import "../BaseModel.h" #import "opencv2/opencv.hpp" @interface ClassificationModel : BaseModel diff --git a/ios/RnExecutorch/models/image_segmentation/Constants.h b/ios/RnExecutorch/models/image_segmentation/Constants.h deleted file mode 100644 index f3d75cd80e..0000000000 --- a/ios/RnExecutorch/models/image_segmentation/Constants.h +++ /dev/null @@ -1,4 +0,0 @@ -#import -#import - -extern const std::vector deeplabv3_resnet50_labels; diff --git a/ios/RnExecutorch/models/image_segmentation/ImageSegmentationModel.h b/ios/RnExecutorch/models/image_segmentation/ImageSegmentationModel.h deleted file mode 100644 index 8d1c76edf0..0000000000 --- a/ios/RnExecutorch/models/image_segmentation/ImageSegmentationModel.h +++ /dev/null @@ -1,10 +0,0 @@ -#import "../BaseModel.h" -#import "opencv2/opencv.hpp" - -@interface ImageSegmentationModel : BaseModel -- (cv::Size)getModelImageSize; -- (NSDictionary *)runModel:(cv::Mat &)input - returnClasses:(NSArray *)classesOfInterest - resize:(BOOL)resize; - -@end diff --git a/ios/RnExecutorch/models/image_segmentation/ImageSegmentationModel.mm b/ios/RnExecutorch/models/image_segmentation/ImageSegmentationModel.mm deleted file mode 100644 index 4ee8c440ed..0000000000 --- a/ios/RnExecutorch/models/image_segmentation/ImageSegmentationModel.mm +++ /dev/null @@ -1,146 +0,0 @@ -#import "ImageSegmentationModel.h" -#import "../../utils/Conversions.h" -#import "../../utils/ImageProcessor.h" -#import "../../utils/Numerical.h" -#import "Constants.h" -#import - -@interface ImageSegmentationModel () -- (NSArray *)preprocess:(cv::Mat &)input; -- (NSDictionary *)postprocess:(NSArray *)output - returnClasses:(NSArray *)classesOfInterest - resize:(BOOL)resize; -@end - -@implementation ImageSegmentationModel { - cv::Size originalSize; -} - -- (cv::Size)getModelImageSize { - NSArray *inputShape = [module getInputShape:@0]; - NSNumber *widthNumber = inputShape.lastObject; - NSNumber *heightNumber = inputShape[inputShape.count - 2]; - - int height = [heightNumber intValue]; - int width = [widthNumber intValue]; - - return cv::Size(height, width); -} - -- (NSArray *)preprocess:(cv::Mat &)input { - originalSize = cv::Size(input.cols, input.rows); - - cv::Size modelImageSize = [self getModelImageSize]; - cv::Mat output; - cv::resize(input, output, modelImageSize); - - NSArray *modelInput = [ImageProcessor matToNSArray:output]; - return modelInput; -} - -std::vector extractResults(NSArray *result, std::size_t numLabels, - cv::Size modelImageSize, - cv::Size originalSize, BOOL resize) { - std::size_t numModelPixels = modelImageSize.height * modelImageSize.width; - - std::vector resizedLabelScores(numLabels); - for (std::size_t label = 0; label < numLabels; ++label) { - cv::Mat labelMat = cv::Mat(modelImageSize, CV_64F); - - for (std::size_t pixel = 0; pixel < numModelPixels; ++pixel) { - int row = pixel / modelImageSize.width; - int col = pixel % modelImageSize.width; - labelMat.at(row, col) = - [result[label * numModelPixels + pixel] doubleValue]; - } - - if (resize) { - cv::resize(labelMat, resizedLabelScores[label], originalSize); - } else { - resizedLabelScores[label] = std::move(labelMat); - } - } - return resizedLabelScores; -} - -void adjustScoresPerPixel(std::vector &labelScores, cv::Mat &argMax, - cv::Size outputSize, std::size_t numLabels) { - std::size_t numOutputPixels = outputSize.height * outputSize.width; - for (std::size_t pixel = 0; pixel < numOutputPixels; ++pixel) { - int row = pixel / outputSize.width; - int col = pixel % outputSize.width; - std::vector scores; - scores.reserve(numLabels); - for (const auto &mat : labelScores) { - scores.push_back(mat.at(row, col)); - } - - std::vector adjustedScores = softmax(scores); - - for (std::size_t label = 0; label < numLabels; ++label) { - labelScores[label].at(row, col) = adjustedScores[label]; - } - - auto maxIt = std::max_element(scores.begin(), scores.end()); - argMax.at(row, col) = std::distance(scores.begin(), maxIt); - } -} - -- (NSDictionary *)postprocess:(NSArray *)output - returnClasses:(NSArray *)classesOfInterest - resize:(BOOL)resize { - cv::Size modelImageSize = [self getModelImageSize]; - - std::size_t numLabels = deeplabv3_resnet50_labels.size(); - - NSAssert((std::size_t)output.count == - numLabels * modelImageSize.height * modelImageSize.width, - @"Model generated unexpected output size."); - - // For each label extract it's matrix, - // and rescale it to the original size if `resize` - std::vector resizedLabelScores = - extractResults(output, numLabels, modelImageSize, originalSize, resize); - - cv::Size outputSize = resize ? originalSize : modelImageSize; - cv::Mat argMax = cv::Mat(outputSize, CV_32S); - - // For each pixel apply softmax across all the labels and calculate the argMax - adjustScoresPerPixel(resizedLabelScores, argMax, outputSize, numLabels); - - std::unordered_set labelSet; - - for (id label in classesOfInterest) { - labelSet.insert(std::string([label UTF8String])); - } - - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - - // Convert to NSArray and populate the final dictionary - for (std::size_t label = 0; label < numLabels; ++label) { - if (labelSet.contains(deeplabv3_resnet50_labels[label])) { - NSString *labelString = @(deeplabv3_resnet50_labels[label].c_str()); - NSArray *arr = simpleMatToNSArray(resizedLabelScores[label]); - result[labelString] = arr; - } - } - - result[@"ARGMAX"] = simpleMatToNSArray(argMax); - - return result; -} - -- (NSDictionary *)runModel:(cv::Mat &)input - returnClasses:(NSArray *)classesOfInterest - resize:(BOOL)resize { - NSArray *modelInput = [self preprocess:input]; - NSArray *result = [self forward:@[ modelInput ]]; - - NSDictionary *output = [self postprocess:result[0] - returnClasses:classesOfInterest - resize:resize]; - - return output; -} - -@end diff --git a/ios/RnExecutorch/models/ocr/Detector.h b/ios/RnExecutorch/models/ocr/Detector.h index 0508144b32..e1a43898c1 100644 --- a/ios/RnExecutorch/models/ocr/Detector.h +++ b/ios/RnExecutorch/models/ocr/Detector.h @@ -1,4 +1,4 @@ -#import "BaseModel.h" +#import "../BaseModel.h" #import "opencv2/opencv.hpp" @interface Detector : BaseModel diff --git a/ios/RnExecutorch/models/ocr/Recognizer.h b/ios/RnExecutorch/models/ocr/Recognizer.h index 4b301dbef7..9d1cd81a04 100644 --- a/ios/RnExecutorch/models/ocr/Recognizer.h +++ b/ios/RnExecutorch/models/ocr/Recognizer.h @@ -1,4 +1,4 @@ -#import "BaseModel.h" +#import "../BaseModel.h" #import "opencv2/opencv.hpp" @interface Recognizer : BaseModel diff --git a/ios/RnExecutorch/models/ocr/VerticalDetector.h b/ios/RnExecutorch/models/ocr/VerticalDetector.h index 10155c5343..87a3e36be5 100644 --- a/ios/RnExecutorch/models/ocr/VerticalDetector.h +++ b/ios/RnExecutorch/models/ocr/VerticalDetector.h @@ -1,4 +1,4 @@ -#import "BaseModel.h" +#import "../BaseModel.h" #import "opencv2/opencv.hpp" @interface VerticalDetector : BaseModel diff --git a/ios/RnExecutorch/models/style_transfer/StyleTransferModel.h b/ios/RnExecutorch/models/style_transfer/StyleTransferModel.h deleted file mode 100644 index 20cdf6dd07..0000000000 --- a/ios/RnExecutorch/models/style_transfer/StyleTransferModel.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "../BaseModel.h" -#import "opencv2/opencv.hpp" - -@interface StyleTransferModel : BaseModel - -- (cv::Size)getModelImageSize; -- (NSArray *)preprocess:(cv::Mat &)input; -- (cv::Mat)postprocess:(NSArray *)output; -- (cv::Mat)runModel:(cv::Mat &)input; - -@end diff --git a/ios/RnExecutorch/models/style_transfer/StyleTransferModel.mm b/ios/RnExecutorch/models/style_transfer/StyleTransferModel.mm deleted file mode 100644 index 8a0665043d..0000000000 --- a/ios/RnExecutorch/models/style_transfer/StyleTransferModel.mm +++ /dev/null @@ -1,50 +0,0 @@ -#import "StyleTransferModel.h" -#import "../../utils/ImageProcessor.h" - -@implementation StyleTransferModel { - cv::Size originalSize; -} - -- (cv::Size)getModelImageSize { - NSArray *inputShape = [module getInputShape:@0]; - NSNumber *widthNumber = inputShape.lastObject; - NSNumber *heightNumber = inputShape[inputShape.count - 2]; - - int height = [heightNumber intValue]; - int width = [widthNumber intValue]; - - return cv::Size(height, width); -} - -- (NSArray *)preprocess:(cv::Mat &)input { - self->originalSize = cv::Size(input.cols, input.rows); - - cv::Size modelImageSize = [self getModelImageSize]; - cv::Mat output; - cv::resize(input, output, modelImageSize); - - NSArray *modelInput = [ImageProcessor matToNSArray:output]; - return modelInput; -} - -- (cv::Mat)postprocess:(NSArray *)output { - cv::Size modelImageSize = [self getModelImageSize]; - cv::Mat processedImage = [ImageProcessor arrayToMat:output - width:modelImageSize.width - height:modelImageSize.height]; - - cv::Mat processedOutput; - cv::resize(processedImage, processedOutput, originalSize); - - return processedOutput; -} - -- (cv::Mat)runModel:(cv::Mat &)input { - NSArray *modelInput = [self preprocess:input]; - NSArray *result = [self forward:@[ modelInput ]]; - input = [self postprocess:result[0]]; - - return input; -} - -@end diff --git a/ios/RnExecutorch/models/text_embeddings/TextEmbeddingsModel.h b/ios/RnExecutorch/models/text_embeddings/TextEmbeddingsModel.h index e26a9228be..be1ac0f95d 100644 --- a/ios/RnExecutorch/models/text_embeddings/TextEmbeddingsModel.h +++ b/ios/RnExecutorch/models/text_embeddings/TextEmbeddingsModel.h @@ -1,4 +1,4 @@ -#import "BaseModel.h" +#import "../BaseModel.h" #import "ExecutorchLib/HuggingFaceTokenizer.h" @interface TextEmbeddingsModel : BaseModel { diff --git a/ios/libs/libbackend_coreml-ios-release.a b/ios/libs/libbackend_coreml-ios-release.a new file mode 100644 index 0000000000..7e85a87872 Binary files /dev/null and b/ios/libs/libbackend_coreml-ios-release.a differ diff --git a/ios/libs/libbackend_coreml-simulator-release.a b/ios/libs/libbackend_coreml-simulator-release.a new file mode 100644 index 0000000000..2a57e256f5 Binary files /dev/null and b/ios/libs/libbackend_coreml-simulator-release.a differ diff --git a/ios/libs/libbackend_mps-ios-release.a b/ios/libs/libbackend_mps-ios-release.a new file mode 100644 index 0000000000..6c8276ca9a Binary files /dev/null and b/ios/libs/libbackend_mps-ios-release.a differ diff --git a/ios/libs/libbackend_mps-simulator-release.a b/ios/libs/libbackend_mps-simulator-release.a new file mode 100644 index 0000000000..abccb7de6e Binary files /dev/null and b/ios/libs/libbackend_mps-simulator-release.a differ diff --git a/ios/libs/libbackend_xnnpack-ios-release.a b/ios/libs/libbackend_xnnpack-ios-release.a new file mode 100644 index 0000000000..f2986123d5 Binary files /dev/null and b/ios/libs/libbackend_xnnpack-ios-release.a differ diff --git a/ios/libs/libbackend_xnnpack-simulator-release.a b/ios/libs/libbackend_xnnpack-simulator-release.a new file mode 100644 index 0000000000..77479199e4 Binary files /dev/null and b/ios/libs/libbackend_xnnpack-simulator-release.a differ diff --git a/ios/libs/libexecutorch-ios-release.a b/ios/libs/libexecutorch-ios-release.a new file mode 100644 index 0000000000..a27e183eb2 Binary files /dev/null and b/ios/libs/libexecutorch-ios-release.a differ diff --git a/ios/libs/libexecutorch-simulator-release.a b/ios/libs/libexecutorch-simulator-release.a new file mode 100644 index 0000000000..d7758b1f01 Binary files /dev/null and b/ios/libs/libexecutorch-simulator-release.a differ diff --git a/ios/libs/libkernels_custom-ios-release.a b/ios/libs/libkernels_custom-ios-release.a new file mode 100644 index 0000000000..cb10deddb6 Binary files /dev/null and b/ios/libs/libkernels_custom-ios-release.a differ diff --git a/ios/libs/libkernels_custom-simulator-release.a b/ios/libs/libkernels_custom-simulator-release.a new file mode 100644 index 0000000000..fea9aa0f59 Binary files /dev/null and b/ios/libs/libkernels_custom-simulator-release.a differ diff --git a/ios/libs/libkernels_optimized-ios-release.a b/ios/libs/libkernels_optimized-ios-release.a new file mode 100644 index 0000000000..9fa35c4c12 Binary files /dev/null and b/ios/libs/libkernels_optimized-ios-release.a differ diff --git a/ios/libs/libkernels_optimized-simulator-release.a b/ios/libs/libkernels_optimized-simulator-release.a new file mode 100644 index 0000000000..ecb16196cc Binary files /dev/null and b/ios/libs/libkernels_optimized-simulator-release.a differ diff --git a/ios/libs/libkernels_portable-ios-release.a b/ios/libs/libkernels_portable-ios-release.a new file mode 100644 index 0000000000..8af1984094 Binary files /dev/null and b/ios/libs/libkernels_portable-ios-release.a differ diff --git a/ios/libs/libkernels_portable-simulator-release.a b/ios/libs/libkernels_portable-simulator-release.a new file mode 100644 index 0000000000..62ab2e3fa2 Binary files /dev/null and b/ios/libs/libkernels_portable-simulator-release.a differ diff --git a/ios/libs/libkernels_quantized-ios-release.a b/ios/libs/libkernels_quantized-ios-release.a new file mode 100644 index 0000000000..f561c77231 Binary files /dev/null and b/ios/libs/libkernels_quantized-ios-release.a differ diff --git a/ios/libs/libkernels_quantized-simulator-release.a b/ios/libs/libkernels_quantized-simulator-release.a new file mode 100644 index 0000000000..f5fee01ef8 Binary files /dev/null and b/ios/libs/libkernels_quantized-simulator-release.a differ diff --git a/react-native-executorch.podspec b/react-native-executorch.podspec index fe3a7094a6..576086790b 100644 --- a/react-native-executorch.podspec +++ b/react-native-executorch.podspec @@ -49,13 +49,31 @@ Pod::Spec.new do |s| } s.pod_target_xcconfig = { - "HEADER_SEARCH_PATHS" => "$(PODS_TARGET_SRCROOT)/third-party/include" + "USE_HEADERMAP" => "YES", + "HEADER_SEARCH_PATHS" => + '"$(PODS_TARGET_SRCROOT)/ios" '+ + '"$(PODS_TARGET_SRCROOT)/third-party/include" '+ + '"$(PODS_TARGET_SRCROOT)/common" ', + "CLANG_CXX_LANGUAGE_STANDARD" => "c++20", } s.ios.vendored_frameworks = "ios/ExecutorchLib.xcframework" - s.source_files = "ios/**/*.{h,m,mm}", "common/**/*.{hpp,cpp,c,h}" + s.source_files = [ + "ios/**/*.{m,mm,h}", + "common/**/*.{cpp,c,h,hpp}", + ] + # Do not include the headers from common/rnexecutorch/jsi/ as source files. + # Xcode/Cocoapods leaks them to other pods that an app also depends on, so if + # another pod includes a header with the same name without a path by + # #include "Header.h" we get a conflict. Here, headers in jsi/ collide with + # react-native-skia. The headers are preserved by preserve_paths and + # then made available by HEADER_SEARCH_PATHS. + s.exclude_files = "common/rnexecutorch/jsi/*.{h,hpp}" + s.header_mappings_dir = "common/rnexecutorch" + s.header_dir = "rnexecutorch" + s.preserve_paths = "common/rnexecutorch/jsi/*.{h,hpp}" - s.dependency "opencv-rne", "~> 0.1.0" + s.dependency "opencv-rne", "~> 4.11.0" s.dependency "sqlite3" install_modules_dependencies(s) diff --git a/src/Error.ts b/src/Error.ts index 433447b7b2..584f9b3edd 100644 --- a/src/Error.ts +++ b/src/Error.ts @@ -27,6 +27,8 @@ export enum ETError { MemoryAllocationFailed = 0x21, AccessFailed = 0x22, InvalidProgram = 0x23, + InvalidExternalData = 0x24, + OutOfResources = 0x25, // Delegate errors DelegateInvalidCompatibility = 0x30, diff --git a/src/hooks/computer_vision/useImageSegmentation.ts b/src/hooks/computer_vision/useImageSegmentation.ts index c3f9f7a824..6b70d68a95 100644 --- a/src/hooks/computer_vision/useImageSegmentation.ts +++ b/src/hooks/computer_vision/useImageSegmentation.ts @@ -1,9 +1,18 @@ -import { useModule } from '../useModule'; +import { ResourceSource } from '../../types/common'; +import { useNonStaticModule } from '../useNonStaticModule'; import { ImageSegmentationModule } from '../../modules/computer_vision/ImageSegmentationModule'; interface Props { - modelSource: string | number; + modelSource: ResourceSource; + preventLoad?: boolean; } -export const useImageSegmentation = ({ modelSource }: Props) => - useModule({ module: ImageSegmentationModule, loadArgs: [modelSource] }); +export const useImageSegmentation = ({ + modelSource, + preventLoad = false, +}: Props) => + useNonStaticModule({ + module: ImageSegmentationModule, + loadArgs: [modelSource], + preventLoad: preventLoad, + }); diff --git a/src/hooks/computer_vision/useStyleTransfer.ts b/src/hooks/computer_vision/useStyleTransfer.ts index e1f6cbe5eb..07a68f4a94 100644 --- a/src/hooks/computer_vision/useStyleTransfer.ts +++ b/src/hooks/computer_vision/useStyleTransfer.ts @@ -1,10 +1,15 @@ import { ResourceSource } from '../../types/common'; -import { useModule } from '../useModule'; +import { useNonStaticModule } from '../useNonStaticModule'; import { StyleTransferModule } from '../../modules/computer_vision/StyleTransferModule'; interface Props { modelSource: ResourceSource; + preventLoad?: boolean; } -export const useStyleTransfer = ({ modelSource }: Props) => - useModule({ module: StyleTransferModule, loadArgs: [modelSource] }); +export const useStyleTransfer = ({ modelSource, preventLoad = false }: Props) => + useNonStaticModule({ + module: StyleTransferModule, + loadArgs: [modelSource], + preventLoad: preventLoad, + }); diff --git a/src/hooks/useNonStaticModule.ts b/src/hooks/useNonStaticModule.ts new file mode 100644 index 0000000000..c02da00c73 --- /dev/null +++ b/src/hooks/useNonStaticModule.ts @@ -0,0 +1,68 @@ +import { useEffect, useState, useMemo } from 'react'; +import { ETError, getError } from '../Error'; + +interface Module { + load: (...args: any[]) => Promise; + forward: (...args: any[]) => Promise; +} + +interface ModuleConstructor { + new (): M; +} + +export const useNonStaticModule = < + M extends Module, + LoadArgs extends Parameters, + ForwardArgs extends any[], + ForwardReturn, +>({ + module, + loadArgs, + preventLoad = false, +}: { + module: ModuleConstructor; + loadArgs: LoadArgs; + preventLoad?: boolean; +}) => { + const [error, setError] = useState(null); + const [isReady, setIsReady] = useState(false); + const [isGenerating, setIsGenerating] = useState(false); + const [downloadProgress, setDownloadProgress] = useState(0); + const model = useMemo(() => new module(), [module]); + + useEffect(() => { + if (!preventLoad) { + (async () => { + setDownloadProgress(0); + setError(null); + try { + setIsReady(false); + await model.load(...loadArgs, setDownloadProgress); + setIsReady(true); + } catch (err) { + setError((err as Error).message); + } + })(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [...loadArgs, preventLoad]); + + const forward = async (...input: ForwardArgs): Promise => { + if (!isReady) throw new Error(getError(ETError.ModuleNotLoaded)); + if (isGenerating) throw new Error(getError(ETError.ModelGenerating)); + try { + setIsGenerating(true); + return await model.forward(...input); + } finally { + setIsGenerating(false); + } + }; + + return { + error, + isReady, + isGenerating, + downloadProgress, + forward, + }; +}; diff --git a/src/index.tsx b/src/index.tsx index b69a7741b0..83de6503bb 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,15 +2,14 @@ import { SpeechToTextLanguage } from './types/stt'; import { ETInstallerNativeModule } from './native/RnExecutorchModules'; -// In the future install pick a symbol to check for to avoid installing multiple times -/* // eslint-disable no-var declare global { - var exampleGlobalFunction: () => void; + var loadStyleTransfer: (source: string) => Promise; + var loadImageSegmentation: (source: string) => Promise; } // eslint-disable no-var -if (global.exampleGlobalFunction == null) { +if (global.loadStyleTransfer == null) { if (!ETInstallerNativeModule) { throw new Error( `Failed to install react-native-executorch: The native module could not be found.` @@ -19,8 +18,6 @@ if (global.exampleGlobalFunction == null) { ETInstallerNativeModule.install(); } -*/ -ETInstallerNativeModule.install(); // hooks export * from './hooks/computer_vision/useClassification'; diff --git a/src/modules/computer_vision/ImageSegmentationModule.ts b/src/modules/computer_vision/ImageSegmentationModule.ts index aaf70ef7bf..2cdbf3ef63 100644 --- a/src/modules/computer_vision/ImageSegmentationModule.ts +++ b/src/modules/computer_vision/ImageSegmentationModule.ts @@ -1,39 +1,45 @@ -import { BaseModule } from '../BaseModule'; -import { getError } from '../../Error'; -import { DeeplabLabel } from '../../types/image_segmentation'; +import { ResourceFetcher } from '../../utils/ResourceFetcher'; import { ResourceSource } from '../../types/common'; -import { ImageSegmentationNativeModule } from '../../native/RnExecutorchModules'; +import { DeeplabLabel } from '../../types/image_segmentation'; +import { ETError, getError } from '../../Error'; -export class ImageSegmentationModule extends BaseModule { - protected static override nativeModule = ImageSegmentationNativeModule; +export class ImageSegmentationModule { + nativeModule: any = null; - static override async load(modelSource: ResourceSource) { - return await super.load(modelSource); + async load( + modelSource: ResourceSource, + onDownloadProgressCallback: (_: number) => void = () => {} + ): Promise { + const paths = await ResourceFetcher.fetchMultipleResources( + onDownloadProgressCallback, + modelSource + ); + this.nativeModule = global.loadImageSegmentation(paths[0] || ''); } - static override async forward( - input: string, + async forward( + imageSource: string, classesOfInterest?: DeeplabLabel[], resize?: boolean ) { - try { - const stringDict = await (this.nativeModule.forward( - input, - (classesOfInterest || []).map((label) => DeeplabLabel[label]), - resize || false - ) as ReturnType<(typeof this.nativeModule)['forward']>); + if (this.nativeModule == null) { + throw new Error(getError(ETError.ModuleNotLoaded)); + } + + const stringDict = await this.nativeModule.forward( + imageSource, + (classesOfInterest || []).map((label) => DeeplabLabel[label]), + resize || false + ); - let enumDict: { [key in DeeplabLabel]?: number[] } = {}; + let enumDict: { [key in DeeplabLabel]?: number[] } = {}; - for (const key in stringDict) { - if (key in DeeplabLabel) { - const enumKey = DeeplabLabel[key as keyof typeof DeeplabLabel]; - enumDict[enumKey] = stringDict[key]; - } + for (const key in stringDict) { + if (key in DeeplabLabel) { + const enumKey = DeeplabLabel[key as keyof typeof DeeplabLabel]; + enumDict[enumKey] = stringDict[key]; } - return enumDict; - } catch (e) { - throw new Error(getError(e)); } + return enumDict; } } diff --git a/src/modules/computer_vision/StyleTransferModule.ts b/src/modules/computer_vision/StyleTransferModule.ts index 77af75e7fb..b8208231af 100644 --- a/src/modules/computer_vision/StyleTransferModule.ts +++ b/src/modules/computer_vision/StyleTransferModule.ts @@ -1,17 +1,24 @@ -import { StyleTransferNativeModule } from '../../native/RnExecutorchModules'; +import { ResourceFetcher } from '../../utils/ResourceFetcher'; import { ResourceSource } from '../../types/common'; -import { BaseModule } from '../BaseModule'; +import { ETError, getError } from '../../Error'; -export class StyleTransferModule extends BaseModule { - protected static override nativeModule = StyleTransferNativeModule; +export class StyleTransferModule { + nativeModule: any = null; - static override async load(modelSource: ResourceSource) { - return await super.load(modelSource); + async load( + modelSource: ResourceSource, + onDownloadProgressCallback: (_: number) => void = () => {} + ): Promise { + const paths = await ResourceFetcher.fetchMultipleResources( + onDownloadProgressCallback, + modelSource + ); + this.nativeModule = global.loadStyleTransfer(paths[0] || ''); } - static override async forward( - input: string - ): ReturnType { - return await this.nativeModule.forward(input); + async forward(imageSource: string) { + if (this.nativeModule == null) + throw new Error(getError(ETError.ModuleNotLoaded)); + return await this.nativeModule.forward(imageSource); } } diff --git a/src/native/NativeImageSegmentation.ts b/src/native/NativeImageSegmentation.ts deleted file mode 100644 index c66c874361..0000000000 --- a/src/native/NativeImageSegmentation.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { TurboModule } from 'react-native'; -import { TurboModuleRegistry } from 'react-native'; - -export interface Spec extends TurboModule { - loadModule(modelSource: string): Promise; - - forward( - input: string, - classesOfInterest: string[], - resize: boolean - ): Promise<{ [category: string]: number[] }>; -} - -export default TurboModuleRegistry.get('ImageSegmentation'); diff --git a/src/native/NativeStyleTransfer.ts b/src/native/NativeStyleTransfer.ts deleted file mode 100644 index 72e3cc03e8..0000000000 --- a/src/native/NativeStyleTransfer.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { TurboModule } from 'react-native'; -import { TurboModuleRegistry } from 'react-native'; - -export interface Spec extends TurboModule { - loadModule(modelSource: string): Promise; - - forward(input: string): Promise; -} - -export default TurboModuleRegistry.get('StyleTransfer'); diff --git a/src/native/RnExecutorchModules.ts b/src/native/RnExecutorchModules.ts index 895c0a7da5..2b9b245e53 100644 --- a/src/native/RnExecutorchModules.ts +++ b/src/native/RnExecutorchModules.ts @@ -1,7 +1,5 @@ import { Platform } from 'react-native'; import { Spec as ObjectDetectionInterface } from './NativeObjectDetection'; -import { Spec as StyleTransferInterface } from './NativeStyleTransfer'; -import { Spec as ImageSegmentationInterface } from './NativeImageSegmentation'; import { Spec as ETModuleInterface } from './NativeETModule'; import { Spec as OCRInterface } from './NativeOCR'; import { Spec as VerticalOCRInterface } from './NativeVerticalOCR'; @@ -39,12 +37,8 @@ const ETModuleNativeModule: ETModuleInterface = returnSpecOrThrowLinkingError( ); const ClassificationNativeModule: ClassificationInterface = returnSpecOrThrowLinkingError(require('./NativeClassification').default); -const ImageSegmentationNativeModule: ImageSegmentationInterface = - returnSpecOrThrowLinkingError(require('./NativeImageSegmentation').default); const ObjectDetectionNativeModule: ObjectDetectionInterface = returnSpecOrThrowLinkingError(require('./NativeObjectDetection').default); -const StyleTransferNativeModule: StyleTransferInterface = - returnSpecOrThrowLinkingError(require('./NativeStyleTransfer').default); const SpeechToTextNativeModule: SpeechToTextInterface = returnSpecOrThrowLinkingError(require('./NativeSpeechToText').default); const OCRNativeModule: OCRInterface = returnSpecOrThrowLinkingError( @@ -65,12 +59,10 @@ export { ETModuleNativeModule, ClassificationNativeModule, ObjectDetectionNativeModule, - StyleTransferNativeModule, - ImageSegmentationNativeModule, SpeechToTextNativeModule, OCRNativeModule, VerticalOCRNativeModule, TextEmbeddingsNativeModule, TokenizerNativeModule, - ETInstallerNativeModule + ETInstallerNativeModule, }; diff --git a/third-party/android/libs/arm64-v8a/libexecutorch.so b/third-party/android/libs/executorch/arm64-v8a/libexecutorch.so similarity index 100% rename from third-party/android/libs/arm64-v8a/libexecutorch.so rename to third-party/android/libs/executorch/arm64-v8a/libexecutorch.so diff --git a/third-party/android/libs/executorch.aar b/third-party/android/libs/executorch/executorch.aar similarity index 100% rename from third-party/android/libs/executorch.aar rename to third-party/android/libs/executorch/executorch.aar diff --git a/third-party/android/libs/x86_64/libexecutorch.so b/third-party/android/libs/executorch/x86_64/libexecutorch.so similarity index 100% rename from third-party/android/libs/x86_64/libexecutorch.so rename to third-party/android/libs/executorch/x86_64/libexecutorch.so diff --git a/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv.a b/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv.a new file mode 100644 index 0000000000..aafb96d52a Binary files /dev/null and b/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv.a differ diff --git a/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv_hal.a b/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv_hal.a new file mode 100644 index 0000000000..2586c51da7 Binary files /dev/null and b/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv_hal.a differ diff --git a/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv_thread.a b/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv_thread.a new file mode 100644 index 0000000000..21b46fd532 Binary files /dev/null and b/third-party/android/libs/opencv-third-party/arm64-v8a/libkleidicv_thread.a differ diff --git a/third-party/android/libs/opencv/arm64-v8a/libopencv_core.a b/third-party/android/libs/opencv/arm64-v8a/libopencv_core.a new file mode 100644 index 0000000000..dfa6cac97b Binary files /dev/null and b/third-party/android/libs/opencv/arm64-v8a/libopencv_core.a differ diff --git a/third-party/android/libs/opencv/arm64-v8a/libopencv_features2d.a b/third-party/android/libs/opencv/arm64-v8a/libopencv_features2d.a new file mode 100644 index 0000000000..2d9285ff48 Binary files /dev/null and b/third-party/android/libs/opencv/arm64-v8a/libopencv_features2d.a differ diff --git a/third-party/android/libs/opencv/arm64-v8a/libopencv_highgui.a b/third-party/android/libs/opencv/arm64-v8a/libopencv_highgui.a new file mode 100644 index 0000000000..f5935c0a49 Binary files /dev/null and b/third-party/android/libs/opencv/arm64-v8a/libopencv_highgui.a differ diff --git a/third-party/android/libs/opencv/arm64-v8a/libopencv_imgproc.a b/third-party/android/libs/opencv/arm64-v8a/libopencv_imgproc.a new file mode 100644 index 0000000000..1230670d37 Binary files /dev/null and b/third-party/android/libs/opencv/arm64-v8a/libopencv_imgproc.a differ diff --git a/third-party/android/libs/opencv/arm64-v8a/libopencv_photo.a b/third-party/android/libs/opencv/arm64-v8a/libopencv_photo.a new file mode 100644 index 0000000000..6fd7b5725c Binary files /dev/null and b/third-party/android/libs/opencv/arm64-v8a/libopencv_photo.a differ diff --git a/third-party/android/libs/opencv/arm64-v8a/libopencv_video.a b/third-party/android/libs/opencv/arm64-v8a/libopencv_video.a new file mode 100644 index 0000000000..94afa14b0c Binary files /dev/null and b/third-party/android/libs/opencv/arm64-v8a/libopencv_video.a differ diff --git a/third-party/android/libs/opencv/x86_64/libopencv_core.a b/third-party/android/libs/opencv/x86_64/libopencv_core.a new file mode 100644 index 0000000000..11dbb38c99 Binary files /dev/null and b/third-party/android/libs/opencv/x86_64/libopencv_core.a differ diff --git a/third-party/android/libs/opencv/x86_64/libopencv_features2d.a b/third-party/android/libs/opencv/x86_64/libopencv_features2d.a new file mode 100644 index 0000000000..7dda0f00f4 Binary files /dev/null and b/third-party/android/libs/opencv/x86_64/libopencv_features2d.a differ diff --git a/third-party/android/libs/opencv/x86_64/libopencv_highgui.a b/third-party/android/libs/opencv/x86_64/libopencv_highgui.a new file mode 100644 index 0000000000..074a6fbd7f Binary files /dev/null and b/third-party/android/libs/opencv/x86_64/libopencv_highgui.a differ diff --git a/third-party/android/libs/opencv/x86_64/libopencv_imgproc.a b/third-party/android/libs/opencv/x86_64/libopencv_imgproc.a new file mode 100644 index 0000000000..af4e846586 Binary files /dev/null and b/third-party/android/libs/opencv/x86_64/libopencv_imgproc.a differ diff --git a/third-party/android/libs/opencv/x86_64/libopencv_photo.a b/third-party/android/libs/opencv/x86_64/libopencv_photo.a new file mode 100644 index 0000000000..d1cd183451 Binary files /dev/null and b/third-party/android/libs/opencv/x86_64/libopencv_photo.a differ diff --git a/third-party/android/libs/opencv/x86_64/libopencv_video.a b/third-party/android/libs/opencv/x86_64/libopencv_video.a new file mode 100644 index 0000000000..6d76f3b5b5 Binary files /dev/null and b/third-party/android/libs/opencv/x86_64/libopencv_video.a differ diff --git a/third-party/include/c10/macros/Export.h b/third-party/include/c10/macros/Export.h new file mode 100644 index 0000000000..771c869ae0 --- /dev/null +++ b/third-party/include/c10/macros/Export.h @@ -0,0 +1,163 @@ +#define C10_USING_CUSTOM_GENERATED_MACROS +#ifndef C10_MACROS_EXPORT_H_ +#define C10_MACROS_EXPORT_H_ + +/* Header file to define the common scaffolding for exported symbols. + * + * Export is by itself a quite tricky situation to deal with, and if you are + * hitting this file, make sure you start with the background here: + * - Linux: https://gcc.gnu.org/wiki/Visibility + * - Windows: + * https://docs.microsoft.com/en-us/cpp/cpp/dllexport-dllimport?view=vs-2017 + * + * Do NOT include this file directly. Instead, use c10/macros/Macros.h + */ + +// You do not need to edit this part of file unless you are changing the core +// pytorch export abstractions. +// +// This part defines the C10 core export and import macros. This is controlled +// by whether we are building shared libraries or not, which is determined +// during build time and codified in c10/core/cmake_macros.h. +// When the library is built as a shared lib, EXPORT and IMPORT will contain +// visibility attributes. If it is being built as a static lib, then EXPORT +// and IMPORT basically have no effect. + +// As a rule of thumb, you should almost NEVER mix static and shared builds for +// libraries that depend on c10. AKA, if c10 is built as a static library, we +// recommend everything dependent on c10 to be built statically. If c10 is built +// as a shared library, everything dependent on it should be built as shared. In +// the PyTorch project, all native libraries shall use the macro +// C10_BUILD_SHARED_LIB to check whether pytorch is building shared or static +// libraries. + +// For build systems that do not directly depend on CMake and directly build +// from the source directory (such as Buck), one may not have a cmake_macros.h +// file at all. In this case, the build system is responsible for providing +// correct macro definitions corresponding to the cmake_macros.h.in file. +// +// In such scenarios, one should define the macro +// C10_USING_CUSTOM_GENERATED_MACROS +// to inform this header that it does not need to include the cmake_macros.h +// file. + +#ifndef C10_USING_CUSTOM_GENERATED_MACROS +#include +#endif // C10_USING_CUSTOM_GENERATED_MACROS + +#ifdef _WIN32 +#define C10_HIDDEN +#if defined(C10_BUILD_SHARED_LIBS) +#define C10_EXPORT __declspec(dllexport) +#define C10_IMPORT __declspec(dllimport) +#else +#define C10_EXPORT +#define C10_IMPORT +#endif +#else // _WIN32 +#if defined(__GNUC__) +#define C10_EXPORT __attribute__((__visibility__("default"))) +#define C10_HIDDEN __attribute__((__visibility__("hidden"))) +#else // defined(__GNUC__) +#define C10_EXPORT +#define C10_HIDDEN +#endif // defined(__GNUC__) +#define C10_IMPORT C10_EXPORT +#endif // _WIN32 + +#ifdef NO_EXPORT +#undef C10_EXPORT +#define C10_EXPORT +#endif + +// Definition of an adaptive XX_API macro, that depends on whether you are +// building the library itself or not, routes to XX_EXPORT and XX_IMPORT. +// Basically, you will need to do this for each shared library that you are +// building, and the instruction is as follows: assuming that you are building +// a library called libawesome.so. You should: +// (1) for your cmake target (usually done by "add_library(awesome, ...)"), +// define a macro called AWESOME_BUILD_MAIN_LIB using +// target_compile_options. +// (2) define the AWESOME_API macro similar to the one below. +// And in the source file of your awesome library, use AWESOME_API to +// annotate public symbols. + +// Here, for the C10 library, we will define the macro C10_API for both import +// and export. + +// This one is being used by libc10.so +#ifdef C10_BUILD_MAIN_LIB +#define C10_API C10_EXPORT +#else +#define C10_API C10_IMPORT +#endif + +// This one is being used by libtorch.so +#ifdef CAFFE2_BUILD_MAIN_LIB +#define TORCH_API C10_EXPORT +#else +#define TORCH_API C10_IMPORT +#endif + +// You may be wondering: Whose brilliant idea was it to split torch_cuda into +// two pieces with confusing names? +// Once upon a time, there _was_ only TORCH_CUDA_API. All was happy until we +// tried to compile PyTorch for CUDA 11.1, which ran into relocation marker +// issues when linking big binaries. +// (https://github.com/pytorch/pytorch/issues/39968) We had two choices: +// (1) Stop supporting so many GPU architectures +// (2) Do something else +// We chose #2 and decided to split the behemoth that was torch_cuda into two +// smaller libraries, one with most of the core kernel functions (torch_cuda_cu) +// and the other that had..well..everything else (torch_cuda_cpp). The idea was +// this: instead of linking our static libraries (like the hefty +// libcudnn_static.a) with another huge library, torch_cuda, and run into pesky +// relocation marker issues, we could link our static libraries to a smaller +// part of torch_cuda (torch_cuda_cpp) and avoid the issues. + +// libtorch_cuda_cu.so +#ifdef TORCH_CUDA_CU_BUILD_MAIN_LIB +#define TORCH_CUDA_CU_API C10_EXPORT +#elif defined(BUILD_SPLIT_CUDA) +#define TORCH_CUDA_CU_API C10_IMPORT +#endif + +// libtorch_cuda_cpp.so +#ifdef TORCH_CUDA_CPP_BUILD_MAIN_LIB +#define TORCH_CUDA_CPP_API C10_EXPORT +#elif defined(BUILD_SPLIT_CUDA) +#define TORCH_CUDA_CPP_API C10_IMPORT +#endif + +// libtorch_cuda.so (where torch_cuda_cu and torch_cuda_cpp are a part of the +// same api) +#ifdef TORCH_CUDA_BUILD_MAIN_LIB +#define TORCH_CUDA_CPP_API C10_EXPORT +#define TORCH_CUDA_CU_API C10_EXPORT +#elif !defined(BUILD_SPLIT_CUDA) +#define TORCH_CUDA_CPP_API C10_IMPORT +#define TORCH_CUDA_CU_API C10_IMPORT +#endif + +#if defined(TORCH_HIP_BUILD_MAIN_LIB) +#define TORCH_HIP_CPP_API C10_EXPORT +#define TORCH_HIP_API C10_EXPORT +#else +#define TORCH_HIP_CPP_API C10_IMPORT +#define TORCH_HIP_API C10_IMPORT +#endif + +#if defined(TORCH_XPU_BUILD_MAIN_LIB) +#define TORCH_XPU_API C10_EXPORT +#else +#define TORCH_XPU_API C10_IMPORT +#endif + +// Enums only need to be exported on windows for non-CUDA files +#if defined(_WIN32) && defined(__CUDACC__) +#define C10_API_ENUM C10_API +#else +#define C10_API_ENUM +#endif + +#endif // C10_MACROS_MACROS_H_ diff --git a/third-party/include/c10/macros/Macros.h b/third-party/include/c10/macros/Macros.h new file mode 100644 index 0000000000..d46e2a369d --- /dev/null +++ b/third-party/include/c10/macros/Macros.h @@ -0,0 +1,497 @@ +#define C10_USING_CUSTOM_GENERATED_MACROS +#ifndef C10_MACROS_MACROS_H_ +#define C10_MACROS_MACROS_H_ +#include + +/* Main entry for c10/macros. + * + * In your code, include c10/macros/Macros.h directly, instead of individual + * files in this folder. + */ + +// For build systems that do not directly depend on CMake and directly build +// from the source directory (such as Buck), one may not have a cmake_macros.h +// file at all. In this case, the build system is responsible for providing +// correct macro definitions corresponding to the cmake_macros.h.in file. +// +// In such scenarios, one should define the macro +// C10_USING_CUSTOM_GENERATED_MACROS +// to inform this header that it does not need to include the cmake_macros.h +// file. + +#ifndef C10_USING_CUSTOM_GENERATED_MACROS +#include +#endif // C10_USING_CUSTOM_GENERATED_MACROS + +#include + +#if defined(__clang__) +#define __ubsan_ignore_float_divide_by_zero__ \ + __attribute__((no_sanitize("float-divide-by-zero"))) +#define __ubsan_ignore_undefined__ __attribute__((no_sanitize("undefined"))) +#define __ubsan_ignore_signed_int_overflow__ \ + __attribute__((no_sanitize("signed-integer-overflow"))) +#define __ubsan_ignore_pointer_overflow__ \ + __attribute__((no_sanitize("pointer-overflow"))) +#define __ubsan_ignore_function__ __attribute__((no_sanitize("function"))) +#define __ubsan_ignore_float_cast_overflow__ \ + __attribute__((no_sanitize("float-cast-overflow"))) +#else +#define __ubsan_ignore_float_divide_by_zero__ +#define __ubsan_ignore_undefined__ +#define __ubsan_ignore_signed_int_overflow__ +#define __ubsan_ignore_pointer_overflow__ +#define __ubsan_ignore_function__ +#define __ubsan_ignore_float_cast_overflow__ +#endif + +// Detect address sanitizer as some stuff doesn't work with it +#undef C10_ASAN_ENABLED + +// for clang +#if defined(__has_feature) +#if ((__has_feature(address_sanitizer))) +#define C10_ASAN_ENABLED 1 +#endif +#endif + +// for gcc +#if defined(__SANITIZE_ADDRESS__) +#if __SANITIZE_ADDRESS__ +#if !defined(C10_ASAN_ENABLED) +#define C10_ASAN_ENABLED 1 +#endif +#endif +#endif + +#if !defined(C10_ASAN_ENABLED) +#define C10_ASAN_ENABLED 0 +#endif + +// Detect undefined-behavior sanitizer (UBSAN) +#undef C10_UBSAN_ENABLED + +// for clang or gcc >= 14 +// NB: gcc 14 adds support for Clang's __has_feature +// https://gcc.gnu.org/gcc-14/changes.html +// gcc < 14 doesn't have a macro for UBSAN +// (e.g. __SANITIZE_UNDEFINED__ does not exist in gcc) +// https://github.com/google/sanitizers/issues/765 +#if defined(__has_feature) +#if ((__has_feature(undefined_behavior_sanitizer))) +#define C10_UBSAN_ENABLED 1 +#endif +#endif + +#if !defined(C10_UBSAN_ENABLED) +#define C10_UBSAN_ENABLED 0 +#endif + +// Disable the copy and assignment operator for a class. Note that this will +// disable the usage of the class in std containers. +#define C10_DISABLE_COPY_AND_ASSIGN(classname) \ + classname(const classname &) = delete; \ + classname &operator=(const classname &) = delete + +#define C10_CONCATENATE_IMPL(s1, s2) s1##s2 +#define C10_CONCATENATE(s1, s2) C10_CONCATENATE_IMPL(s1, s2) + +#define C10_MACRO_EXPAND(args) args + +#define C10_STRINGIZE_IMPL(x) #x +#define C10_STRINGIZE(x) C10_STRINGIZE_IMPL(x) + +/** + * C10_ANONYMOUS_VARIABLE(str) introduces a new identifier which starts with + * str and ends with a unique number. + */ +#ifdef __COUNTER__ +#define C10_UID __COUNTER__ +#define C10_ANONYMOUS_VARIABLE(str) C10_CONCATENATE(str, __COUNTER__) +#else +#define C10_UID __LINE__ +#define C10_ANONYMOUS_VARIABLE(str) C10_CONCATENATE(str, __LINE__) +#endif + +#ifdef __has_cpp_attribute +#define C10_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +#define C10_HAS_CPP_ATTRIBUTE(x) (0) +#endif + +#ifndef FBCODE_CAFFE2 +/// DEPRECATED: Warn if a type or return value is discarded. +#define C10_NODISCARD [[nodiscard]] + +/// DEPRECATED: Suppress an unused variable. +#define C10_UNUSED [[maybe_unused]] +#endif + +#if !defined(__has_attribute) +#define __has_attribute(x) 0 +#endif + +// Direct port of LLVM_ATTRIBUTE_USED. +#if __has_attribute(used) +#define C10_USED __attribute__((__used__)) +#else +#define C10_USED +#endif + +#define C10_RESTRICT __restrict + +// Simply define the namespace, in case a dependent library want to refer to +// the c10 namespace but not any nontrivial files. +namespace c10 {} +namespace c10::cuda {} +namespace c10::hip {} +namespace c10::xpu {} + +// Since C10 is the core library for caffe2 (and aten), we will simply reroute +// all abstractions defined in c10 to be available in caffe2 as well. +// This is only for backwards compatibility. Please use the symbols from the +// c10 namespace where possible. +namespace caffe2 { +using namespace c10; +} +namespace at { +using namespace c10; +} +namespace at::cuda { +using namespace c10::cuda; +} // namespace at::cuda + +// WARNING!!! THIS IS A GIANT HACK!!! +// This line means you cannot simultaneously include c10/hip +// and c10/cuda and then use them from the at::cuda namespace. +// This is true in practice, because HIPIFY works inplace on +// files in ATen/cuda, so it assumes that c10::hip is available +// from at::cuda. This namespace makes that happen. When +// HIPIFY is no longer out-of-place, we can switch the cuda +// here to hip and everyone is happy. +namespace at::cuda { +using namespace c10::hip; +} // namespace at::cuda + +namespace at::xpu { +using namespace c10::xpu; +} // namespace at::xpu + +// C10_LIKELY/C10_UNLIKELY +// +// These macros provide parentheses, so you can use these macros as: +// +// if C10_LIKELY(some_expr) { +// ... +// } +// +// NB: static_cast to boolean is mandatory in C++, because __builtin_expect +// takes a long argument, which means you may trigger the wrong conversion +// without it. +// +#if defined(__GNUC__) || defined(__ICL) || defined(__clang__) +#define C10_LIKELY(expr) (__builtin_expect(static_cast(expr), 1)) +#define C10_UNLIKELY(expr) (__builtin_expect(static_cast(expr), 0)) +#else +#define C10_LIKELY(expr) (expr) +#define C10_UNLIKELY(expr) (expr) +#endif + +/// C10_NOINLINE - Functions whose declaration is annotated with this will not +/// be inlined. +#ifdef __GNUC__ +#define C10_NOINLINE __attribute__((noinline)) +#elif _MSC_VER +#define C10_NOINLINE __declspec(noinline) +#else +#define C10_NOINLINE +#endif + +#if defined(_MSC_VER) +#define C10_ALWAYS_INLINE __forceinline +#elif __has_attribute(always_inline) || defined(__GNUC__) +#define C10_ALWAYS_INLINE __attribute__((__always_inline__)) inline +#else +#define C10_ALWAYS_INLINE inline +#endif + +// Unlike C10_ALWAYS_INLINE, C10_ALWAYS_INLINE_ATTRIBUTE can be used +// on a lambda. +#if defined(_MSC_VER) +// MSVC 14.39 is reasonably recent and doesn't like +// [[msvc::forceinline]] on a lambda, so don't try to use it. +#define C10_ALWAYS_INLINE_ATTRIBUTE +#elif __has_attribute(always_inline) || defined(__GNUC__) +#define C10_ALWAYS_INLINE_ATTRIBUTE __attribute__((__always_inline__)) +#else +#define C10_ALWAYS_INLINE_ATTRIBUTE +#endif + +#if defined(_MSC_VER) +#define C10_ATTR_VISIBILITY_HIDDEN +#elif defined(__GNUC__) +#define C10_ATTR_VISIBILITY_HIDDEN __attribute__((__visibility__("hidden"))) +#else +#define C10_ATTR_VISIBILITY_HIDDEN +#endif + +#define C10_ERASE C10_ALWAYS_INLINE C10_ATTR_VISIBILITY_HIDDEN + +#include + +#ifdef __HIPCC__ +// Unlike CUDA, HIP requires a HIP header to be included for __host__ to work. +// We do this #include here so that C10_HOST_DEVICE and friends will Just Work. +// See https://github.com/ROCm-Developer-Tools/HIP/issues/441 +#include +#endif + +#if defined(__CUDACC__) || defined(__HIPCC__) +// Designates functions callable from the host (CPU) and the device (GPU) +#define C10_HOST_DEVICE __host__ __device__ +#define C10_DEVICE __device__ +#define C10_HOST __host__ +// constants from +// (https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical-specifications) +// The maximum number of threads per multiprocessor is 1024 for Turing +// architecture (7.5), 1536 for Geforce Ampere (8.6)/Jetson Orin (8.7), and +// 2048 for all other architectures. You'll get warnings if you exceed these +// constants. Hence, the following macros adjust the input values from the user +// to resolve potential warnings. +#if __CUDA_ARCH__ == 750 +constexpr uint32_t CUDA_MAX_THREADS_PER_SM = 1024; +#elif __CUDA_ARCH__ == 860 || __CUDA_ARCH__ == 870 || __CUDA_ARCH__ == 890 +constexpr uint32_t CUDA_MAX_THREADS_PER_SM = 1536; +#else +constexpr uint32_t CUDA_MAX_THREADS_PER_SM = 2048; +#endif +// CUDA_MAX_THREADS_PER_BLOCK is same for all architectures currently +constexpr uint32_t CUDA_MAX_THREADS_PER_BLOCK = 1024; +// CUDA_THREADS_PER_BLOCK_FALLBACK is the "canonical fallback" choice of block +// size. 256 is a good number for this fallback and should give good occupancy +// and versatility across all architectures. +constexpr uint32_t CUDA_THREADS_PER_BLOCK_FALLBACK = 256; +// NOTE: if you are thinking of constexpr-ify the inputs to launch bounds, it +// turns out that although __launch_bounds__ can take constexpr, it +// can't take a constexpr that has anything to do with templates. +// Currently we use launch_bounds that depend on template arguments in +// Loops.cuh, Reduce.cuh and LossCTC.cuh. Hence, C10_MAX_THREADS_PER_BLOCK +// and C10_MIN_BLOCKS_PER_SM are kept as macros. +// Suppose you were planning to write __launch_bounds__(a, b), based on your +// performance tuning on a modern GPU. Instead, you should write +// __launch_bounds__(C10_MAX_THREADS_PER_BLOCK(a), C10_MIN_BLOCKS_PER_SM(a, b)), +// which will also properly respect limits on old architectures. +#define C10_MAX_THREADS_PER_BLOCK(val) \ + (((val) <= CUDA_MAX_THREADS_PER_BLOCK) ? (val) \ + : CUDA_THREADS_PER_BLOCK_FALLBACK) +#define C10_MIN_BLOCKS_PER_SM(threads_per_block, blocks_per_sm) \ + ((((threads_per_block) * (blocks_per_sm) <= CUDA_MAX_THREADS_PER_SM) \ + ? (blocks_per_sm) \ + : ((CUDA_MAX_THREADS_PER_SM + (threads_per_block) - 1) / \ + (threads_per_block)))) +// C10_LAUNCH_BOUNDS is analogous to __launch_bounds__ +#define C10_LAUNCH_BOUNDS_0 \ + __launch_bounds__(256, \ + 4) // default launch bounds that should give good occupancy + // and versatility across all architectures. +#define C10_LAUNCH_BOUNDS_1(max_threads_per_block) \ + __launch_bounds__((C10_MAX_THREADS_PER_BLOCK((max_threads_per_block)))) +#define C10_LAUNCH_BOUNDS_2(max_threads_per_block, min_blocks_per_sm) \ + __launch_bounds__( \ + (C10_MAX_THREADS_PER_BLOCK((max_threads_per_block))), \ + (C10_MIN_BLOCKS_PER_SM((max_threads_per_block), (min_blocks_per_sm)))) +#else +#define C10_HOST_DEVICE +#define C10_HOST +#define C10_DEVICE +#endif + +#if defined(USE_ROCM) +#define C10_HIP_HOST_DEVICE __host__ __device__ +#else +#define C10_HIP_HOST_DEVICE +#endif + +#if defined(USE_ROCM) +#define C10_WARP_SIZE warpSize // = 64 or 32 (Defined in hip_runtime.h) +#else +#define C10_WARP_SIZE 32 +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +#define __func__ __FUNCTION__ +#endif + +// CUDA_KERNEL_ASSERT checks the assertion +// even when NDEBUG is defined. This is useful for important assertions in CUDA +// code that would otherwise be suppressed when building Release. +#if defined(__ANDROID__) || defined(__APPLE__) || defined(__FreeBSD__) +// Those platforms do not support assert() +#define CUDA_KERNEL_ASSERT(cond) +#define CUDA_KERNEL_ASSERT_MSG(cond, msg) +#define SYCL_KERNEL_ASSERT(cond) +#elif defined(_MSC_VER) +#if defined(NDEBUG) +extern "C" { +C10_IMPORT +#if defined(__SYCL_DEVICE_ONLY__) +extern SYCL_EXTERNAL void _wassert(const wchar_t *wexpr, const wchar_t *wfile, + unsigned line); +#else +#if defined(__CUDA_ARCH__) +__host__ __device__ +#endif // __CUDA_ARCH__ + void + _wassert(wchar_t const *_Message, wchar_t const *_File, unsigned _Line); +#endif // __SYCL_DEVICE_ONLY__ +} +#endif // NDEBUG +#define CUDA_KERNEL_ASSERT(cond) \ + if (C10_UNLIKELY(!(cond))) { \ + (void)(_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), \ + static_cast(__LINE__)), \ + 0); \ + } +// TODO: This doesn't assert the message because I (chilli) couldn't figure out +// a nice way to convert a char* to a wchar_t* +#define CUDA_KERNEL_ASSERT_MSG(cond, msg) \ + if (C10_UNLIKELY(!(cond))) { \ + (void)(_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), \ + static_cast(__LINE__)), \ + 0); \ + } +#define SYCL_KERNEL_ASSERT(cond) \ + if (C10_UNLIKELY(!(cond))) { \ + (void)(_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), \ + static_cast(__LINE__)), \ + 0); \ + } +#else // __APPLE__, _MSC_VER +#if defined(NDEBUG) +extern "C" { +#if defined(__SYCL_DEVICE_ONLY__) +extern SYCL_EXTERNAL void __assert_fail(const char *expr, const char *file, + unsigned int line, const char *func); +#else // __SYCL_DEVICE_ONLY__ +#if (defined(__CUDA_ARCH__) && !(defined(__clang__) && defined(__CUDA__))) +// CUDA supports __assert_fail function which are common for both device +// and host side code. +__host__ __device__ +#endif + + // This forward declaration matching the declaration of __assert_fail + // exactly how it is in glibc in case parts of the program are compiled with + // different NDEBUG settings. Otherwise we might get 'ambiguous declaration' + // error. Note: On ROCm - this declaration serves for host side compilation. + void + __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function) noexcept __attribute__((__noreturn__)); + +#endif // __SYCL_DEVICE_ONLY__ +} +#endif // NDEBUG +// ROCm disable kernel assert by default +#if !defined(C10_USE_ROCM_KERNEL_ASSERT) and defined(USE_ROCM) +#define CUDA_KERNEL_ASSERT(cond) +#define CUDA_KERNEL_ASSERT_MSG(cond, msg) +#define SYCL_KERNEL_ASSERT(cond) +#else +#define CUDA_KERNEL_ASSERT(cond) \ + if (C10_UNLIKELY(!(cond))) { \ + __assert_fail(#cond, __FILE__, static_cast(__LINE__), \ + __func__); \ + } +#define CUDA_KERNEL_ASSERT_MSG(cond, msg) \ + if (C10_UNLIKELY(!(cond))) { \ + __assert_fail(msg, __FILE__, static_cast(__LINE__), \ + __func__); \ + } +#define SYCL_KERNEL_ASSERT(cond) \ + if (C10_UNLIKELY(!(cond))) { \ + __assert_fail(#cond, __FILE__, static_cast(__LINE__), \ + __func__); \ + } +#endif // C10_USE_ROCM_KERNEL_ASSERT and USE_ROCM +#endif // __APPLE__ + +#ifdef __APPLE__ +#include +#endif + +#if defined(__ANDROID__) +#define C10_ANDROID 1 +#define C10_MOBILE 1 +#elif (defined(__APPLE__) && \ + (TARGET_IPHONE_SIMULATOR || TARGET_OS_SIMULATOR || TARGET_OS_IPHONE)) +#define C10_IOS 1 +#define C10_MOBILE 1 +#endif // ANDROID / IOS + +#if defined(C10_MOBILE) && C10_MOBILE +#define C10_ALWAYS_INLINE_UNLESS_MOBILE inline +#else +#define C10_ALWAYS_INLINE_UNLESS_MOBILE C10_ALWAYS_INLINE +#endif + +#if !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED) +#define CONSTEXPR_EXCEPT_WIN_CUDA constexpr +#define C10_HOST_CONSTEXPR_EXCEPT_WIN_CUDA constexpr + +#define STATIC_CONSTEXPR_STR_INL_EXCEPT_WIN_CUDA(field, val) \ + static constexpr const char field[] = val; +#define STATIC_CONST_STR_OUT_OF_LINE_FOR_WIN_CUDA(cls, field, val) +#endif // !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED) + +#ifndef HAS_DEMANGLE +#if defined(__ANDROID__) || defined(_WIN32) || defined(__EMSCRIPTEN__) +#define HAS_DEMANGLE 0 +#elif defined(__APPLE__) && \ + (TARGET_IPHONE_SIMULATOR || TARGET_OS_SIMULATOR || TARGET_OS_IPHONE) +#define HAS_DEMANGLE 0 +#else +#define HAS_DEMANGLE 1 +#endif +#endif // HAS_DEMANGLE + +#define _C10_PRAGMA__(string) _Pragma(#string) +#define _C10_PRAGMA_(string) _C10_PRAGMA__(string) + +#ifdef __clang__ +#define C10_CLANG_DIAGNOSTIC_PUSH() _Pragma("clang diagnostic push") +#define C10_CLANG_DIAGNOSTIC_POP() _Pragma("clang diagnostic pop") +#define C10_CLANG_DIAGNOSTIC_IGNORE(flag) \ + _C10_PRAGMA_(clang diagnostic ignored flag) +#define C10_CLANG_HAS_WARNING(flag) __has_warning(flag) +#else +#define C10_CLANG_DIAGNOSTIC_PUSH() +#define C10_CLANG_DIAGNOSTIC_POP() +#define C10_CLANG_DIAGNOSTIC_IGNORE(flag) +#define C10_CLANG_HAS_WARNING(flag) 0 +#endif + +#ifdef __clang__ + +#define C10_DIAGNOSTIC_PUSH_AND_IGNORED_IF_DEFINED(warning) \ + _C10_PRAGMA_(clang diagnostic push) \ + _C10_PRAGMA_(clang diagnostic ignored "-Wunknown-warning-option") \ + _C10_PRAGMA_(clang diagnostic ignored warning) + +#define C10_DIAGNOSTIC_POP() _C10_PRAGMA_(clang diagnostic pop) + +#elif __GNUC__ + +#define C10_DIAGNOSTIC_PUSH_AND_IGNORED_IF_DEFINED(warning) \ + _C10_PRAGMA_(GCC diagnostic push) \ + _C10_PRAGMA_(GCC diagnostic ignored "-Wpragmas") \ + _C10_PRAGMA_(GCC diagnostic ignored warning) + +#define C10_DIAGNOSTIC_POP() _C10_PRAGMA_(GCC diagnostic pop) + +#else + +#define C10_DIAGNOSTIC_PUSH_AND_IGNORED_IF_DEFINED(warning) +#define C10_DIAGNOSTIC_POP() + +#endif + +#endif // C10_MACROS_MACROS_H_ diff --git a/third-party/include/c10/util/BFloat16-inl.h b/third-party/include/c10/util/BFloat16-inl.h new file mode 100644 index 0000000000..d37a19d510 --- /dev/null +++ b/third-party/include/c10/util/BFloat16-inl.h @@ -0,0 +1,342 @@ +#pragma once + +#include +#include + +#include + +C10_CLANG_DIAGNOSTIC_PUSH() +#if C10_CLANG_HAS_WARNING("-Wimplicit-int-float-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") +#endif + +#if defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) +#if defined(CL_SYCL_LANGUAGE_VERSION) +#include // for SYCL 1.2.1 +#else +#include // for SYCL 2020 +#endif +#include +#endif + +namespace c10 { + +/// Constructors +inline C10_HOST_DEVICE BFloat16::BFloat16(float value) + : +#if defined(__CUDACC__) && !defined(USE_ROCM) && defined(__CUDA_ARCH__) && \ + __CUDA_ARCH__ >= 800 + x(__bfloat16_as_ushort(__float2bfloat16(value))) +#elif defined(__SYCL_DEVICE_ONLY__) && \ + defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) + x(c10::bit_cast(sycl::ext::oneapi::bfloat16(value))) +#else + // RNE by default + x(detail::round_to_nearest_even(value)) +#endif +{ +} + +/// Implicit conversions +inline C10_HOST_DEVICE BFloat16::operator float() const { +#if defined(__CUDACC__) && !defined(USE_ROCM) + return __bfloat162float(*reinterpret_cast(&x)); +#elif defined(__SYCL_DEVICE_ONLY__) && \ + defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) + return float(*reinterpret_cast(&x)); +#else + return detail::f32_from_bits(x); +#endif +} + +#if defined(__CUDACC__) && !defined(USE_ROCM) +inline C10_HOST_DEVICE BFloat16::BFloat16(const __nv_bfloat16 &value) { + x = *reinterpret_cast(&value); +} +inline C10_HOST_DEVICE BFloat16::operator __nv_bfloat16() const { + return *reinterpret_cast(&x); +} +#endif + +#if defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) +inline C10_HOST_DEVICE +BFloat16::BFloat16(const sycl::ext::oneapi::bfloat16 &value) { + x = *reinterpret_cast(&value); +} +inline C10_HOST_DEVICE BFloat16::operator sycl::ext::oneapi::bfloat16() const { + return *reinterpret_cast(&x); +} +#endif + +// CUDA intrinsics + +#if defined(__CUDACC__) || defined(__HIPCC__) +inline C10_DEVICE BFloat16 __ldg(const BFloat16 *ptr) { +#if !defined(USE_ROCM) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 + return __ldg(reinterpret_cast(ptr)); +#else + return *ptr; +#endif +} +#endif + +/// Arithmetic + +inline C10_HOST_DEVICE BFloat16 operator+(const BFloat16 &a, + const BFloat16 &b) { + return static_cast(a) + static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator-(const BFloat16 &a, + const BFloat16 &b) { + return static_cast(a) - static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator*(const BFloat16 &a, + const BFloat16 &b) { + return static_cast(a) * static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator/(const BFloat16 &a, const BFloat16 &b) + __ubsan_ignore_float_divide_by_zero__ { + return static_cast(a) / static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator-(const BFloat16 &a) { + return -static_cast(a); +} + +inline C10_HOST_DEVICE BFloat16 &operator+=(BFloat16 &a, const BFloat16 &b) { + a = a + b; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator-=(BFloat16 &a, const BFloat16 &b) { + a = a - b; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator*=(BFloat16 &a, const BFloat16 &b) { + a = a * b; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator/=(BFloat16 &a, const BFloat16 &b) { + a = a / b; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator|(BFloat16 &a, const BFloat16 &b) { + a.x = a.x | b.x; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator^(BFloat16 &a, const BFloat16 &b) { + a.x = a.x ^ b.x; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator&(BFloat16 &a, const BFloat16 &b) { + a.x = a.x & b.x; + return a; +} + +/// Arithmetic with floats + +inline C10_HOST_DEVICE float operator+(BFloat16 a, float b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE float operator-(BFloat16 a, float b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE float operator*(BFloat16 a, float b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE float operator/(BFloat16 a, float b) { + return static_cast(a) / b; +} + +inline C10_HOST_DEVICE float operator+(float a, BFloat16 b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE float operator-(float a, BFloat16 b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE float operator*(float a, BFloat16 b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE float operator/(float a, BFloat16 b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE float &operator+=(float &a, const BFloat16 &b) { + return a += static_cast(b); +} +inline C10_HOST_DEVICE float &operator-=(float &a, const BFloat16 &b) { + return a -= static_cast(b); +} +inline C10_HOST_DEVICE float &operator*=(float &a, const BFloat16 &b) { + return a *= static_cast(b); +} +inline C10_HOST_DEVICE float &operator/=(float &a, const BFloat16 &b) { + return a /= static_cast(b); +} + +/// Arithmetic with doubles + +inline C10_HOST_DEVICE double operator+(BFloat16 a, double b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE double operator-(BFloat16 a, double b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE double operator*(BFloat16 a, double b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE double operator/(BFloat16 a, double b) { + return static_cast(a) / b; +} + +inline C10_HOST_DEVICE double operator+(double a, BFloat16 b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE double operator-(double a, BFloat16 b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE double operator*(double a, BFloat16 b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE double operator/(double a, BFloat16 b) { + return a / static_cast(b); +} + +/// Arithmetic with ints + +inline C10_HOST_DEVICE BFloat16 operator+(BFloat16 a, int b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator-(BFloat16 a, int b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator*(BFloat16 a, int b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator/(BFloat16 a, int b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator+(int a, BFloat16 b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE BFloat16 operator-(int a, BFloat16 b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE BFloat16 operator*(int a, BFloat16 b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE BFloat16 operator/(int a, BFloat16 b) { + return static_cast(a) / b; +} + +//// Arithmetic with int64_t + +inline C10_HOST_DEVICE BFloat16 operator+(BFloat16 a, int64_t b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator-(BFloat16 a, int64_t b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator*(BFloat16 a, int64_t b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator/(BFloat16 a, int64_t b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator+(int64_t a, BFloat16 b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE BFloat16 operator-(int64_t a, BFloat16 b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE BFloat16 operator*(int64_t a, BFloat16 b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE BFloat16 operator/(int64_t a, BFloat16 b) { + return static_cast(a) / b; +} + +// Overloading < and > operators, because std::max and std::min use them. + +inline C10_HOST_DEVICE bool operator>(BFloat16 &lhs, BFloat16 &rhs) { + return float(lhs) > float(rhs); +} + +inline C10_HOST_DEVICE bool operator<(BFloat16 &lhs, BFloat16 &rhs) { + return float(lhs) < float(rhs); +} + +} // namespace c10 + +namespace std { + +template <> class numeric_limits { +public: + static constexpr bool is_signed = true; + static constexpr bool is_specialized = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + static constexpr auto has_denorm = numeric_limits::has_denorm; + static constexpr auto has_denorm_loss = + numeric_limits::has_denorm_loss; + static constexpr auto round_style = numeric_limits::round_style; + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 8; + static constexpr int digits10 = 2; + static constexpr int max_digits10 = 4; + static constexpr int radix = 2; + static constexpr int min_exponent = -125; + static constexpr int min_exponent10 = -37; + static constexpr int max_exponent = 128; + static constexpr int max_exponent10 = 38; + static constexpr auto traps = numeric_limits::traps; + static constexpr auto tinyness_before = + numeric_limits::tinyness_before; + + static constexpr c10::BFloat16 min() { + return c10::BFloat16(0x0080, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 lowest() { + return c10::BFloat16(0xFF7F, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 max() { + return c10::BFloat16(0x7F7F, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 epsilon() { + return c10::BFloat16(0x3C00, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 round_error() { + return c10::BFloat16(0x3F00, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 infinity() { + return c10::BFloat16(0x7F80, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 quiet_NaN() { + return c10::BFloat16(0x7FC0, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 signaling_NaN() { + return c10::BFloat16(0x7F80, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 denorm_min() { + return c10::BFloat16(0x0001, c10::BFloat16::from_bits()); + } +}; + +} // namespace std + +C10_CLANG_DIAGNOSTIC_POP() diff --git a/third-party/include/c10/util/BFloat16-math.h b/third-party/include/c10/util/BFloat16-math.h new file mode 100644 index 0000000000..e5c7419261 --- /dev/null +++ b/third-party/include/c10/util/BFloat16-math.h @@ -0,0 +1,266 @@ +#pragma once + +#include +#include + +C10_CLANG_DIAGNOSTIC_PUSH() +#if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion") +#endif + +namespace c10 { +template +struct is_reduced_floating_point + : std::integral_constant || + std::is_same_v> {}; + +template +constexpr bool is_reduced_floating_point_v = + is_reduced_floating_point::value; +} // namespace c10 + +namespace std { + +#if !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED) +using c10::is_reduced_floating_point; +using c10::is_reduced_floating_point_v; +#endif // !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED) + +template , int> = 0> +inline T acos(T a) { + return std::acos(float(a)); +} +template , int> = 0> +inline T asin(T a) { + return std::asin(float(a)); +} +template , int> = 0> +inline T atan(T a) { + return std::atan(float(a)); +} +template , int> = 0> +inline T atanh(T a) { + return std::atanh(float(a)); +} +template , int> = 0> +inline T erf(T a) { + return std::erf(float(a)); +} +template , int> = 0> +inline T erfc(T a) { + return std::erfc(float(a)); +} +template , int> = 0> +inline T exp(T a) { + return std::exp(float(a)); +} +template , int> = 0> +inline T expm1(T a) { + return std::expm1(float(a)); +} +template , int> = 0> +inline bool isfinite(T a) { + return std::isfinite(float(a)); +} +template , int> = 0> +inline T log(T a) { + return std::log(float(a)); +} +template , int> = 0> +inline T log10(T a) { + return std::log10(float(a)); +} +template , int> = 0> +inline T log1p(T a) { + return std::log1p(float(a)); +} +template , int> = 0> +inline T log2(T a) { + return std::log2(float(a)); +} +template , int> = 0> +inline T ceil(T a) { + return std::ceil(float(a)); +} +template , int> = 0> +inline T cos(T a) { + return std::cos(float(a)); +} +template , int> = 0> +inline T floor(T a) { + return std::floor(float(a)); +} +template , int> = 0> +inline T nearbyint(T a) { + return std::nearbyint(float(a)); +} +template , int> = 0> +inline T sin(T a) { + return std::sin(float(a)); +} +template , int> = 0> +inline T tan(T a) { + return std::tan(float(a)); +} +template , int> = 0> +inline T sinh(T a) { + return std::sinh(float(a)); +} +template , int> = 0> +inline T cosh(T a) { + return std::cosh(float(a)); +} +template , int> = 0> +inline T tanh(T a) { + return std::tanh(float(a)); +} +template , int> = 0> +inline T trunc(T a) { + return std::trunc(float(a)); +} +template , int> = 0> +inline T lgamma(T a) { + return std::lgamma(float(a)); +} +template , int> = 0> +inline T sqrt(T a) { + return std::sqrt(float(a)); +} +template , int> = 0> +inline T rsqrt(T a) { + return 1.0 / std::sqrt(float(a)); +} +template , int> = 0> +inline T abs(T a) { + return std::abs(float(a)); +} +#if defined(_MSC_VER) && defined(__CUDACC__) +template , int> = 0> +inline T pow(T a, double b) { + return std::pow(float(a), float(b)); +} +#else +template , int> = 0> +inline T pow(T a, double b) { + return std::pow(float(a), b); +} +#endif +template , int> = 0> +inline T pow(T a, T b) { + return std::pow(float(a), float(b)); +} +template , int> = 0> +inline T fmod(T a, T b) { + return std::fmod(float(a), float(b)); +} + +/* + The following function is inspired from the implementation in `musl` + Link to License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT + ---------------------------------------------------------------------- + Copyright © 2005-2020 Rich Felker, et al. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ---------------------------------------------------------------------- + */ +template , int> = 0> +C10_HOST_DEVICE inline T nextafter(T from, T to) { + // Reference: + // https://git.musl-libc.org/cgit/musl/tree/src/math/nextafter.c + using int_repr_t = uint16_t; + constexpr uint8_t bits = 16; + union { + T f; + int_repr_t i; + } ufrom = {from}, uto = {to}; + + // get a mask to get the sign bit i.e. MSB + int_repr_t sign_mask = int_repr_t{1} << (bits - 1); + + // short-circuit: if either is NaN, return NaN + if (from != from || to != to) { + return from + to; + } + + // short-circuit: if they are exactly the same. + if (ufrom.i == uto.i) { + return from; + } + + // mask the sign-bit to zero i.e. positive + // equivalent to abs(x) + int_repr_t abs_from = ufrom.i & ~sign_mask; + int_repr_t abs_to = uto.i & ~sign_mask; + if (abs_from == 0) { + // if both are zero but with different sign, + // preserve the sign of `to`. + if (abs_to == 0) { + return to; + } + // smallest subnormal with sign of `to`. + ufrom.i = (uto.i & sign_mask) | int_repr_t{1}; + return ufrom.f; + } + + // if abs(from) > abs(to) or sign(from) != sign(to) + if (abs_from > abs_to || ((ufrom.i ^ uto.i) & sign_mask)) { + ufrom.i--; + } else { + ufrom.i++; + } + + return ufrom.f; +} + +} // namespace std + +C10_CLANG_DIAGNOSTIC_POP() diff --git a/third-party/include/c10/util/BFloat16.h b/third-party/include/c10/util/BFloat16.h new file mode 100644 index 0000000000..e457e6dcc1 --- /dev/null +++ b/third-party/include/c10/util/BFloat16.h @@ -0,0 +1,125 @@ +#pragma once + +// Defines the bloat16 type (brain floating-point). This representation uses +// 1 bit for the sign, 8 bits for the exponent and 7 bits for the mantissa. + +#include +#include +#include +#include +#include +#include + +#if defined(__CUDACC__) && !defined(USE_ROCM) +#include +#endif + +#if defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) +#if defined(CL_SYCL_LANGUAGE_VERSION) +#include // for SYCL 1.2.1 +#else +#include // for SYCL 2020 +#endif +#include +#endif + +namespace c10 { + +namespace detail { +inline C10_HOST_DEVICE float f32_from_bits(uint16_t src) { + float res = 0; + uint32_t tmp = src; + tmp <<= 16; + +#if defined(USE_ROCM) + float *tempRes; + + // We should be using memcpy in order to respect the strict aliasing rule + // but it fails in the HIP environment. + tempRes = reinterpret_cast(&tmp); + res = *tempRes; +#else + std::memcpy(&res, &tmp, sizeof(tmp)); +#endif + + return res; +} + +inline C10_HOST_DEVICE uint16_t bits_from_f32(float src) { + uint32_t res = 0; + +#if defined(USE_ROCM) + // We should be using memcpy in order to respect the strict aliasing rule + // but it fails in the HIP environment. + uint32_t *tempRes = reinterpret_cast(&src); + res = *tempRes; +#else + std::memcpy(&res, &src, sizeof(res)); +#endif + + return res >> 16; +} + +inline C10_HOST_DEVICE uint16_t round_to_nearest_even(float src) { +#if defined(USE_ROCM) + if (src != src) { +#elif defined(_MSC_VER) + if (isnan(src)) { +#else + if (std::isnan(src)) { +#endif + return UINT16_C(0x7FC0); + } else { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + union { + uint32_t U32; // NOLINT(facebook-hte-BadMemberName) + float F32; // NOLINT(facebook-hte-BadMemberName) + }; + + F32 = src; + uint32_t rounding_bias = ((U32 >> 16) & 1) + UINT32_C(0x7FFF); + return static_cast((U32 + rounding_bias) >> 16); + } +} +} // namespace detail + +struct alignas(2) BFloat16 { + uint16_t x; + + // HIP wants __host__ __device__ tag, CUDA does not +#if defined(USE_ROCM) + C10_HOST_DEVICE BFloat16() = default; +#else + BFloat16() = default; +#endif + + struct from_bits_t {}; + static constexpr C10_HOST_DEVICE from_bits_t from_bits() { + return from_bits_t(); + } + + constexpr C10_HOST_DEVICE BFloat16(unsigned short bits, from_bits_t) + : x(bits) {} + /* implicit */ inline C10_HOST_DEVICE BFloat16(float value); + inline C10_HOST_DEVICE operator float() const; + +#if defined(__CUDACC__) && !defined(USE_ROCM) + inline C10_HOST_DEVICE BFloat16(const __nv_bfloat16 &value); + explicit inline C10_HOST_DEVICE operator __nv_bfloat16() const; +#endif + +#if defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) + inline C10_HOST_DEVICE BFloat16(const sycl::ext::oneapi::bfloat16 &value); + explicit inline C10_HOST_DEVICE operator sycl::ext::oneapi::bfloat16() const; +#endif +}; + +C10_API inline std::ostream &operator<<(std::ostream &out, + const BFloat16 &value) { + out << (float)value; + return out; +} + +} // namespace c10 + +#include // IWYU pragma: keep diff --git a/third-party/include/c10/util/Half-inl.h b/third-party/include/c10/util/Half-inl.h new file mode 100644 index 0000000000..df2824bb69 --- /dev/null +++ b/third-party/include/c10/util/Half-inl.h @@ -0,0 +1,347 @@ +#pragma once + +#include +#include + +#include +#include + +#ifdef __CUDACC__ +#include +#endif + +#ifdef __HIPCC__ +#include +#endif + +#if defined(CL_SYCL_LANGUAGE_VERSION) +#include // for SYCL 1.2.1 +#elif defined(SYCL_LANGUAGE_VERSION) +#include // for SYCL 2020 +#endif + +#if (defined(CPU_CAPABILITY_AVX2) || defined(CPU_CAPABILITY_AVX512)) && \ + !defined(__APPLE__) +#include +#endif + +C10_CLANG_DIAGNOSTIC_PUSH() +#if C10_CLANG_HAS_WARNING("-Wimplicit-int-float-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") +#endif + +namespace c10 { + +#if defined(__aarch64__) && !defined(__CUDACC__) +/// Constructors +inline Half::Half(float16_t value) : x(detail::fp16_to_bits(value)) {} +inline Half::operator float16_t() const { return detail::fp16_from_bits(x); } +#else + +inline C10_HOST_DEVICE Half::Half(float value) + : +#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__) + x(__half_as_short(__float2half(value))) +#elif defined(__SYCL_DEVICE_ONLY__) + x(c10::bit_cast(sycl::half(value))) +#elif (defined(CPU_CAPABILITY_AVX2) || defined(CPU_CAPABILITY_AVX512)) && \ + !defined(__APPLE__) + x(at::vec::float2half_scalar(value)) +#else + x(detail::fp16_ieee_from_fp32_value(value)) +#endif +{ +} + +/// Implicit conversions + +inline C10_HOST_DEVICE Half::operator float() const { +#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__) + return __half2float(*reinterpret_cast(&x)); +#elif defined(__SYCL_DEVICE_ONLY__) + return float(c10::bit_cast(x)); +#elif (defined(CPU_CAPABILITY_AVX2) || defined(CPU_CAPABILITY_AVX512)) && \ + !defined(__APPLE__) + return at::vec::half2float_scalar(x); +#elif defined(__aarch64__) && !defined(__CUDACC__) + return detail::native_fp16_to_fp32_value(x); +#else + return detail::fp16_ieee_to_fp32_value(x); +#endif +} + +#endif /* !defined(__aarch64__) || defined(__CUDACC__) \ + */ + +#if defined(__CUDACC__) || defined(__HIPCC__) +inline C10_HOST_DEVICE Half::Half(const __half &value) { + x = *reinterpret_cast(&value); +} +inline C10_HOST_DEVICE Half::operator __half() const { + return *reinterpret_cast(&x); +} +#endif + +#ifdef SYCL_LANGUAGE_VERSION +inline C10_HOST_DEVICE Half::Half(const sycl::half &value) { + x = *reinterpret_cast(&value); +} +inline C10_HOST_DEVICE Half::operator sycl::half() const { + return *reinterpret_cast(&x); +} +#endif + +// CUDA intrinsics + +#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 350)) || \ + (defined(__clang__) && defined(__CUDA__)) +inline __device__ Half __ldg(const Half *ptr) { + return __ldg(reinterpret_cast(ptr)); +} +#endif + +/// Arithmetic + +inline C10_HOST_DEVICE Half operator+(const Half &a, const Half &b) { + return static_cast(a) + static_cast(b); +} + +inline C10_HOST_DEVICE Half operator-(const Half &a, const Half &b) { + return static_cast(a) - static_cast(b); +} + +inline C10_HOST_DEVICE Half operator*(const Half &a, const Half &b) { + return static_cast(a) * static_cast(b); +} + +inline C10_HOST_DEVICE Half operator/(const Half &a, const Half &b) + __ubsan_ignore_float_divide_by_zero__ { + return static_cast(a) / static_cast(b); +} + +inline C10_HOST_DEVICE Half operator-(const Half &a) { +#if (defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530) || \ + defined(__HIP_DEVICE_COMPILE__) + return __hneg(a); +#elif defined(__SYCL_DEVICE_ONLY__) + return -c10::bit_cast(a); +#else + return -static_cast(a); +#endif +} + +inline C10_HOST_DEVICE Half &operator+=(Half &a, const Half &b) { + a = a + b; + return a; +} + +inline C10_HOST_DEVICE Half &operator-=(Half &a, const Half &b) { + a = a - b; + return a; +} + +inline C10_HOST_DEVICE Half &operator*=(Half &a, const Half &b) { + a = a * b; + return a; +} + +inline C10_HOST_DEVICE Half &operator/=(Half &a, const Half &b) { + a = a / b; + return a; +} + +/// Arithmetic with floats + +inline C10_HOST_DEVICE float operator+(Half a, float b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE float operator-(Half a, float b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE float operator*(Half a, float b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE float +operator/(Half a, float b) __ubsan_ignore_float_divide_by_zero__ { + return static_cast(a) / b; +} + +inline C10_HOST_DEVICE float operator+(float a, Half b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE float operator-(float a, Half b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE float operator*(float a, Half b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE float +operator/(float a, Half b) __ubsan_ignore_float_divide_by_zero__ { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE float &operator+=(float &a, const Half &b) { + return a += static_cast(b); +} +inline C10_HOST_DEVICE float &operator-=(float &a, const Half &b) { + return a -= static_cast(b); +} +inline C10_HOST_DEVICE float &operator*=(float &a, const Half &b) { + return a *= static_cast(b); +} +inline C10_HOST_DEVICE float &operator/=(float &a, const Half &b) { + return a /= static_cast(b); +} + +/// Arithmetic with doubles + +inline C10_HOST_DEVICE double operator+(Half a, double b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE double operator-(Half a, double b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE double operator*(Half a, double b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE double +operator/(Half a, double b) __ubsan_ignore_float_divide_by_zero__ { + return static_cast(a) / b; +} + +inline C10_HOST_DEVICE double operator+(double a, Half b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE double operator-(double a, Half b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE double operator*(double a, Half b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE double +operator/(double a, Half b) __ubsan_ignore_float_divide_by_zero__ { + return a / static_cast(b); +} + +/// Arithmetic with ints + +inline C10_HOST_DEVICE Half operator+(Half a, int b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE Half operator-(Half a, int b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE Half operator*(Half a, int b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE Half operator/(Half a, int b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE Half operator+(int a, Half b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE Half operator-(int a, Half b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE Half operator*(int a, Half b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE Half operator/(int a, Half b) { + return static_cast(a) / b; +} + +//// Arithmetic with int64_t + +inline C10_HOST_DEVICE Half operator+(Half a, int64_t b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE Half operator-(Half a, int64_t b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE Half operator*(Half a, int64_t b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE Half operator/(Half a, int64_t b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE Half operator+(int64_t a, Half b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE Half operator-(int64_t a, Half b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE Half operator*(int64_t a, Half b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE Half operator/(int64_t a, Half b) { + return static_cast(a) / b; +} + +/// NOTE: we do not define comparisons directly and instead rely on the implicit +/// conversion from c10::Half to float. + +} // namespace c10 + +namespace std { + +template <> class numeric_limits { +public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + static constexpr auto has_denorm = numeric_limits::has_denorm; + static constexpr auto has_denorm_loss = + numeric_limits::has_denorm_loss; + static constexpr auto round_style = numeric_limits::round_style; + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 11; + static constexpr int digits10 = 3; + static constexpr int max_digits10 = 5; + static constexpr int radix = 2; + static constexpr int min_exponent = -13; + static constexpr int min_exponent10 = -4; + static constexpr int max_exponent = 16; + static constexpr int max_exponent10 = 4; + static constexpr auto traps = numeric_limits::traps; + static constexpr auto tinyness_before = + numeric_limits::tinyness_before; + static constexpr c10::Half min() { + return c10::Half(0x0400, c10::Half::from_bits()); + } + static constexpr c10::Half lowest() { + return c10::Half(0xFBFF, c10::Half::from_bits()); + } + static constexpr c10::Half max() { + return c10::Half(0x7BFF, c10::Half::from_bits()); + } + static constexpr c10::Half epsilon() { + return c10::Half(0x1400, c10::Half::from_bits()); + } + static constexpr c10::Half round_error() { + return c10::Half(0x3800, c10::Half::from_bits()); + } + static constexpr c10::Half infinity() { + return c10::Half(0x7C00, c10::Half::from_bits()); + } + static constexpr c10::Half quiet_NaN() { + return c10::Half(0x7E00, c10::Half::from_bits()); + } + static constexpr c10::Half signaling_NaN() { + return c10::Half(0x7D00, c10::Half::from_bits()); + } + static constexpr c10::Half denorm_min() { + return c10::Half(0x0001, c10::Half::from_bits()); + } +}; + +} // namespace std + +C10_CLANG_DIAGNOSTIC_POP() diff --git a/third-party/include/c10/util/Half.h b/third-party/include/c10/util/Half.h new file mode 100644 index 0000000000..8c32762c1a --- /dev/null +++ b/third-party/include/c10/util/Half.h @@ -0,0 +1,416 @@ +#pragma once + +/// Defines the Half type (half-precision floating-point) including conversions +/// to standard C types and basic arithmetic operations. Note that arithmetic +/// operations are implemented by converting to floating point and +/// performing the operation in float32, instead of using CUDA half intrinsics. +/// Most uses of this type within ATen are memory bound, including the +/// element-wise kernels, and the half intrinsics aren't efficient on all GPUs. +/// If you are writing a compute bound kernel, you can use the CUDA half +/// intrinsics directly on the Half type from device code. + +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +#include +#elif !defined(__OPENCL_VERSION__) +#include +#endif + +#ifdef _MSC_VER +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef __CUDACC__ +#include +#endif + +#ifdef __HIPCC__ +#include +#endif + +#if defined(CL_SYCL_LANGUAGE_VERSION) +#include // for SYCL 1.2.1 +#elif defined(SYCL_LANGUAGE_VERSION) +#include // for SYCL 2020 +#endif + +#if defined(__aarch64__) && !defined(__CUDACC__) +#include +#endif + +#if defined(__GNUC__) || defined(__clang__) +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \ + defined(_M_IX86) +#if defined(__F16C__) && !(defined(__CUDA_ARCH__) || defined(__CUDACC__) || \ + defined(__HIP_DEVICE_COMPILE__)) +#define C10_X86_F16 1 +#include // import conversion ops from f16cintrin.h +#endif // defined(__F16C__) && !(defined(__CUDA_ARCH__) || defined(__CUDACC__) + // || defined(__HIP_DEVICE_COMPILE__)) +#endif // __x86_64__ || _M_X64 || __i386 || _M_IX86 +#endif // __GNUC__ || __clang__ + +namespace c10 { + +namespace detail { + +/* + * Convert a 16-bit floating-point number in IEEE half-precision format, in bit + * representation, to a 32-bit floating-point number in IEEE single-precision + * format, in bit representation. + * + * @note The implementation doesn't use any floating-point operations. + */ +inline uint32_t fp16_ieee_to_fp32_bits(uint16_t h) { + /* + * Extend the half-precision floating-point number to 32 bits and shift to the + * upper part of the 32-bit word: + * +---+-----+------------+-------------------+ + * | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| + * +---+-----+------------+-------------------+ + * Bits 31 26-30 16-25 0-15 + * + * S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 + * - zero bits. + */ + const uint32_t w = (uint32_t)h << 16; + /* + * Extract the sign of the input number into the high bit of the 32-bit word: + * + * +---+----------------------------------+ + * | S |0000000 00000000 00000000 00000000| + * +---+----------------------------------+ + * Bits 31 0-31 + */ + const uint32_t sign = w & UINT32_C(0x80000000); + /* + * Extract mantissa and biased exponent of the input number into the bits 0-30 + * of the 32-bit word: + * + * +---+-----+------------+-------------------+ + * | 0 |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| + * +---+-----+------------+-------------------+ + * Bits 30 27-31 17-26 0-16 + */ + const uint32_t nonsign = w & UINT32_C(0x7FFFFFFF); + /* + * Renorm shift is the number of bits to shift mantissa left to make the + * half-precision number normalized. If the initial number is normalized, some + * of its high 6 bits (sign == 0 and 5-bit exponent) equals one. In this case + * renorm_shift == 0. If the number is denormalize, renorm_shift > 0. Note + * that if we shift denormalized nonsign by renorm_shift, the unit bit of + * mantissa will shift into exponent, turning the biased exponent into 1, and + * making mantissa normalized (i.e. without leading 1). + */ +#ifdef _MSC_VER + unsigned long nonsign_bsr; + _BitScanReverse(&nonsign_bsr, (unsigned long)nonsign); + uint32_t renorm_shift = (uint32_t)nonsign_bsr ^ 31; +#else + uint32_t renorm_shift = __builtin_clz(nonsign); +#endif + renorm_shift = renorm_shift > 5 ? renorm_shift - 5 : 0; + /* + * Iff half-precision number has exponent of 15, the addition overflows + * it into bit 31, and the subsequent shift turns the high 9 bits + * into 1. Thus inf_nan_mask == 0x7F800000 if the half-precision number + * had exponent of 15 (i.e. was NaN or infinity) 0x00000000 otherwise + */ + const int32_t inf_nan_mask = + ((int32_t)(nonsign + 0x04000000) >> 8) & INT32_C(0x7F800000); + /* + * Iff nonsign is 0, it overflows into 0xFFFFFFFF, turning bit 31 + * into 1. Otherwise, bit 31 remains 0. The signed shift right by 31 + * broadcasts bit 31 into all bits of the zero_mask. Thus zero_mask == + * 0xFFFFFFFF if the half-precision number was zero (+0.0h or -0.0h) + * 0x00000000 otherwise + */ + const int32_t zero_mask = (int32_t)(nonsign - 1) >> 31; + /* + * 1. Shift nonsign left by renorm_shift to normalize it (if the input + * was denormal) + * 2. Shift nonsign right by 3 so the exponent (5 bits originally) + * becomes an 8-bit field and 10-bit mantissa shifts into the 10 high + * bits of the 23-bit mantissa of IEEE single-precision number. + * 3. Add 0x70 to the exponent (starting at bit 23) to compensate the + * different in exponent bias (0x7F for single-precision number less 0xF + * for half-precision number). + * 4. Subtract renorm_shift from the exponent (starting at bit 23) to + * account for renormalization. As renorm_shift is less than 0x70, this + * can be combined with step 3. + * 5. Binary OR with inf_nan_mask to turn the exponent into 0xFF if the + * input was NaN or infinity. + * 6. Binary ANDNOT with zero_mask to turn the mantissa and exponent + * into zero if the input was zero. + * 7. Combine with the sign of the input number. + */ + return sign | + ((((nonsign << renorm_shift >> 3) + ((0x70 - renorm_shift) << 23)) | + inf_nan_mask) & + ~zero_mask); +} + +/* + * Convert a 16-bit floating-point number in IEEE half-precision format, in bit + * representation, to a 32-bit floating-point number in IEEE single-precision + * format. + * + * @note The implementation relies on IEEE-like (no assumption about rounding + * mode and no operations on denormals) floating-point operations and bitcasts + * between integer and floating-point variables. + */ +C10_HOST_DEVICE inline float fp16_ieee_to_fp32_value(uint16_t h) { +#ifdef C10_X86_F16 + return _cvtsh_ss(h); +#else + /* + * Extend the half-precision floating-point number to 32 bits and shift to the + * upper part of the 32-bit word: + * +---+-----+------------+-------------------+ + * | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| + * +---+-----+------------+-------------------+ + * Bits 31 26-30 16-25 0-15 + * + * S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 + * - zero bits. + */ + const uint32_t w = (uint32_t)h << 16; + /* + * Extract the sign of the input number into the high bit of the 32-bit word: + * + * +---+----------------------------------+ + * | S |0000000 00000000 00000000 00000000| + * +---+----------------------------------+ + * Bits 31 0-31 + */ + const uint32_t sign = w & UINT32_C(0x80000000); + /* + * Extract mantissa and biased exponent of the input number into the high bits + * of the 32-bit word: + * + * +-----+------------+---------------------+ + * |EEEEE|MM MMMM MMMM|0 0000 0000 0000 0000| + * +-----+------------+---------------------+ + * Bits 27-31 17-26 0-16 + */ + const uint32_t two_w = w + w; + + /* + * Shift mantissa and exponent into bits 23-28 and bits 13-22 so they become + * mantissa and exponent of a single-precision floating-point number: + * + * S|Exponent | Mantissa + * +-+---+-----+------------+----------------+ + * |0|000|EEEEE|MM MMMM MMMM|0 0000 0000 0000| + * +-+---+-----+------------+----------------+ + * Bits | 23-31 | 0-22 + * + * Next, there are some adjustments to the exponent: + * - The exponent needs to be corrected by the difference in exponent bias + * between single-precision and half-precision formats (0x7F - 0xF = 0x70) + * - Inf and NaN values in the inputs should become Inf and NaN values after + * conversion to the single-precision number. Therefore, if the biased + * exponent of the half-precision input was 0x1F (max possible value), the + * biased exponent of the single-precision output must be 0xFF (max possible + * value). We do this correction in two steps: + * - First, we adjust the exponent by (0xFF - 0x1F) = 0xE0 (see exp_offset + * below) rather than by 0x70 suggested by the difference in the exponent bias + * (see above). + * - Then we multiply the single-precision result of exponent adjustment by + * 2**(-112) to reverse the effect of exponent adjustment by 0xE0 less the + * necessary exponent adjustment by 0x70 due to difference in exponent bias. + * The floating-point multiplication hardware would ensure than Inf and + * NaN would retain their value on at least partially IEEE754-compliant + * implementations. + * + * Note that the above operations do not handle denormal inputs (where biased + * exponent == 0). However, they also do not operate on denormal inputs, and + * do not produce denormal results. + */ + constexpr uint32_t exp_offset = UINT32_C(0xE0) << 23; + // const float exp_scale = 0x1.0p-112f; + constexpr uint32_t scale_bits = (uint32_t)15 << 23; + float exp_scale_val = 0; + std::memcpy(&exp_scale_val, &scale_bits, sizeof(exp_scale_val)); + const float exp_scale = exp_scale_val; + const float normalized_value = + fp32_from_bits((two_w >> 4) + exp_offset) * exp_scale; + + /* + * Convert denormalized half-precision inputs into single-precision results + * (always normalized). Zero inputs are also handled here. + * + * In a denormalized number the biased exponent is zero, and mantissa has + * on-zero bits. First, we shift mantissa into bits 0-9 of the 32-bit word. + * + * zeros | mantissa + * +---------------------------+------------+ + * |0000 0000 0000 0000 0000 00|MM MMMM MMMM| + * +---------------------------+------------+ + * Bits 10-31 0-9 + * + * Now, remember that denormalized half-precision numbers are represented as: + * FP16 = mantissa * 2**(-24). + * The trick is to construct a normalized single-precision number with the + * same mantissa and thehalf-precision input and with an exponent which would + * scale the corresponding mantissa bits to 2**(-24). A normalized + * single-precision floating-point number is represented as: FP32 = (1 + + * mantissa * 2**(-23)) * 2**(exponent - 127) Therefore, when the biased + * exponent is 126, a unit change in the mantissa of the input denormalized + * half-precision number causes a change of the constructed single-precision + * number by 2**(-24), i.e. the same amount. + * + * The last step is to adjust the bias of the constructed single-precision + * number. When the input half-precision number is zero, the constructed + * single-precision number has the value of FP32 = 1 * 2**(126 - 127) = + * 2**(-1) = 0.5 Therefore, we need to subtract 0.5 from the constructed + * single-precision number to get the numerical equivalent of the input + * half-precision number. + */ + constexpr uint32_t magic_mask = UINT32_C(126) << 23; + constexpr float magic_bias = 0.5f; + const float denormalized_value = + fp32_from_bits((two_w >> 17) | magic_mask) - magic_bias; + + /* + * - Choose either results of conversion of input as a normalized number, or + * as a denormalized number, depending on the input exponent. The variable + * two_w contains input exponent in bits 27-31, therefore if its smaller than + * 2**27, the input is either a denormal number, or zero. + * - Combine the result of conversion of exponent and mantissa with the sign + * of the input number. + */ + constexpr uint32_t denormalized_cutoff = UINT32_C(1) << 27; + const uint32_t result = + sign | (two_w < denormalized_cutoff ? fp32_to_bits(denormalized_value) + : fp32_to_bits(normalized_value)); + return fp32_from_bits(result); +#endif // C10_X86_F16 +} + +/* + * Convert a 32-bit floating-point number in IEEE single-precision format to a + * 16-bit floating-point number in IEEE half-precision format, in bit + * representation. + * + * @note The implementation relies on IEEE-like (no assumption about rounding + * mode and no operations on denormals) floating-point operations and bitcasts + * between integer and floating-point variables. + */ +inline uint16_t fp16_ieee_from_fp32_value(float f) { +#ifdef C10_X86_F16 + return _cvtss_sh(f, _MM_FROUND_TO_NEAREST_INT); +#else + // const float scale_to_inf = 0x1.0p+112f; + // const float scale_to_zero = 0x1.0p-110f; + constexpr uint32_t scale_to_inf_bits = (uint32_t)239 << 23; + constexpr uint32_t scale_to_zero_bits = (uint32_t)17 << 23; + float scale_to_inf_val = 0, scale_to_zero_val = 0; + std::memcpy(&scale_to_inf_val, &scale_to_inf_bits, sizeof(scale_to_inf_val)); + std::memcpy(&scale_to_zero_val, &scale_to_zero_bits, + sizeof(scale_to_zero_val)); + const float scale_to_inf = scale_to_inf_val; + const float scale_to_zero = scale_to_zero_val; + +#if defined(_MSC_VER) && _MSC_VER == 1916 + float base = ((signbit(f) != 0 ? -f : f) * scale_to_inf) * scale_to_zero; +#else + float base = (fabsf(f) * scale_to_inf) * scale_to_zero; +#endif + + const uint32_t w = fp32_to_bits(f); + const uint32_t shl1_w = w + w; + const uint32_t sign = w & UINT32_C(0x80000000); + uint32_t bias = shl1_w & UINT32_C(0xFF000000); + if (bias < UINT32_C(0x71000000)) { + bias = UINT32_C(0x71000000); + } + + base = fp32_from_bits((bias >> 1) + UINT32_C(0x07800000)) + base; + const uint32_t bits = fp32_to_bits(base); + const uint32_t exp_bits = (bits >> 13) & UINT32_C(0x00007C00); + const uint32_t mantissa_bits = bits & UINT32_C(0x00000FFF); + const uint32_t nonsign = exp_bits + mantissa_bits; + return static_cast( + (sign >> 16) | + (shl1_w > UINT32_C(0xFF000000) ? UINT16_C(0x7E00) : nonsign)); +#endif // C10_X86_F16 +} + +#ifdef C10_X86_F16 +#undef C10_X86_F16 +#endif // C10_X86_F16 + +#if defined(__aarch64__) && !defined(__CUDACC__) +inline float16_t fp16_from_bits(uint16_t h) { + return c10::bit_cast(h); +} + +inline uint16_t fp16_to_bits(float16_t f) { return c10::bit_cast(f); } + +// According to https://godbolt.org/z/frExdbsWG it would translate to single +// fcvt s0, h0 +inline float native_fp16_to_fp32_value(uint16_t h) { + return static_cast(fp16_from_bits(h)); +} + +inline uint16_t native_fp16_from_fp32_value(float f) { + return fp16_to_bits(static_cast(f)); +} +#endif + +} // namespace detail + +struct alignas(2) Half { + unsigned short x; + + struct from_bits_t {}; + C10_HOST_DEVICE static constexpr from_bits_t from_bits() { + return from_bits_t(); + } + + // HIP wants __host__ __device__ tag, CUDA does not +#if defined(USE_ROCM) + C10_HOST_DEVICE Half() = default; +#else + Half() = default; +#endif + + constexpr C10_HOST_DEVICE Half(unsigned short bits, from_bits_t) : x(bits) {} +#if defined(__aarch64__) && !defined(__CUDACC__) + inline Half(float16_t value); + inline operator float16_t() const; +#else + inline C10_HOST_DEVICE Half(float value); + inline C10_HOST_DEVICE operator float() const; +#endif + +#if defined(__CUDACC__) || defined(__HIPCC__) + inline C10_HOST_DEVICE Half(const __half &value); + inline C10_HOST_DEVICE operator __half() const; +#endif +#ifdef SYCL_LANGUAGE_VERSION + inline C10_HOST_DEVICE Half(const sycl::half &value); + inline C10_HOST_DEVICE operator sycl::half() const; +#endif +}; + +C10_API inline std::ostream &operator<<(std::ostream &out, const Half &value) { + out << (float)value; + return out; +} + +} // namespace c10 + +#include // IWYU pragma: keep diff --git a/third-party/include/c10/util/TypeSafeSignMath.h b/third-party/include/c10/util/TypeSafeSignMath.h new file mode 100644 index 0000000000..3ec70e6b69 --- /dev/null +++ b/third-party/include/c10/util/TypeSafeSignMath.h @@ -0,0 +1,133 @@ +#pragma once + +#include +#include +#include + +C10_CLANG_DIAGNOSTIC_PUSH() +#if C10_CLANG_HAS_WARNING("-Wstring-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wstring-conversion") +#endif +#if C10_CLANG_HAS_WARNING("-Wimplicit-int-float-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") +#endif + +namespace c10 { + +/// Returns false since we cannot have x < 0 if x is unsigned. +template +inline constexpr bool is_negative(const T & /*x*/, + std::true_type /*is_unsigned*/) { + return false; +} + +/// Returns true if a signed variable x < 0 +template +inline constexpr bool is_negative(const T &x, std::false_type /*is_unsigned*/) { + return x < T(0); +} + +/// Returns true if x < 0 +/// NOTE: Will fail on an unsigned custom type +/// For the most part it's possible to fix this if +/// the custom type has a constexpr constructor. +/// However, notably, c10::Half does not :-( +template inline constexpr bool is_negative(const T &x) { + return is_negative(x, std::is_unsigned()); +} + +/// Returns the sign of an unsigned variable x as 0, 1 +template +inline constexpr int signum(const T &x, std::true_type /*is_unsigned*/) { + return T(0) < x; +} + +/// Returns the sign of a signed variable x as -1, 0, 1 +template +inline constexpr int signum(const T &x, std::false_type /*is_unsigned*/) { + return (T(0) < x) - (x < T(0)); +} + +/// Returns the sign of x as -1, 0, 1 +/// NOTE: Will fail on an unsigned custom type +/// For the most part it's possible to fix this if +/// the custom type has a constexpr constructor. +/// However, notably, c10::Half does not :-( +template inline constexpr int signum(const T &x) { + return signum(x, std::is_unsigned()); +} + +/// Returns true if a and b are not both negative +template +inline constexpr bool signs_differ(const T &a, const U &b) { + return is_negative(a) != is_negative(b); +} + +// Suppress sign compare warning when compiling with GCC +// as later does not account for short-circuit rule before +// raising the warning, see https://godbolt.org/z/Tr3Msnz99 +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#endif + +/// Returns true if x is greater than the greatest value of the type Limit +template +inline constexpr bool greater_than_max(const T &x) { + constexpr bool can_overflow = + std::numeric_limits::digits > std::numeric_limits::digits; + return can_overflow && x > std::numeric_limits::max(); +} + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +/// Returns true if x < lowest(Limit). Standard comparison +template +inline constexpr bool less_than_lowest(const T &x, + std::false_type /*limit_is_unsigned*/, + std::false_type /*x_is_unsigned*/) { + return x < std::numeric_limits::lowest(); +} + +/// Returns false since all the limit is signed and therefore includes +/// negative values but x cannot be negative because it is unsigned +template +inline constexpr bool less_than_lowest(const T & /*x*/, + std::false_type /*limit_is_unsigned*/, + std::true_type /*x_is_unsigned*/) { + return false; +} + +/// Returns true if x < 0, where 0 is constructed from T. +/// Limit is not signed, so its lower value is zero +template +inline constexpr bool less_than_lowest(const T &x, + std::true_type /*limit_is_unsigned*/, + std::false_type /*x_is_unsigned*/) { + return x < T(0); +} + +/// Returns false sign both types are unsigned +template +inline constexpr bool less_than_lowest(const T & /*x*/, + std::true_type /*limit_is_unsigned*/, + std::true_type /*x_is_unsigned*/) { + return false; +} + +/// Returns true if x is less than the lowest value of type T +/// NOTE: Will fail on an unsigned custom type +/// For the most part it's possible to fix this if +/// the custom type has a constexpr constructor. +/// However, notably, c10::Half does not : +template +inline constexpr bool less_than_lowest(const T &x) { + return less_than_lowest(x, std::is_unsigned(), + std::is_unsigned()); +} + +} // namespace c10 + +C10_CLANG_DIAGNOSTIC_POP() diff --git a/third-party/include/c10/util/bit_cast.h b/third-party/include/c10/util/bit_cast.h new file mode 100644 index 0000000000..640c9c0294 --- /dev/null +++ b/third-party/include/c10/util/bit_cast.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#if __has_include() && (__cplusplus >= 202002L || (defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L)) +#include +#define C10_HAVE_STD_BIT_CAST 1 +#else +#define C10_HAVE_STD_BIT_CAST 0 +#endif // __has_include() && (__cplusplus >= 202002L || + // (defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L)) + +namespace c10 { + +#if C10_HAVE_STD_BIT_CAST +using std::bit_cast; +#else +// Implementations of std::bit_cast() from C++ 20. +// +// This is a less sketchy version of reinterpret_cast. +// +// See https://en.cppreference.com/w/cpp/numeric/bit_cast for more +// information as well as the source of our implementations. +template +std::enable_if_t && + std::is_trivially_copyable_v, + To> +// constexpr support needs compiler magic +bit_cast(const From &src) noexcept { + static_assert(std::is_trivially_constructible_v, + "This implementation additionally requires " + "destination type to be trivially constructible"); + + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; +} +#endif // C10_HAVE_STD_BIT_CAST +#undef C10_HAVE_STD_BIT_CAST + +} // namespace c10 diff --git a/third-party/include/c10/util/floating_point_utils.h b/third-party/include/c10/util/floating_point_utils.h new file mode 100644 index 0000000000..b240c4ea23 --- /dev/null +++ b/third-party/include/c10/util/floating_point_utils.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +namespace c10::detail { + +C10_HOST_DEVICE inline float fp32_from_bits(uint32_t w) { +#if defined(__OPENCL_VERSION__) + return as_float(w); +#elif defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__) + return __uint_as_float((unsigned int)w); +#elif defined(__INTEL_COMPILER) + return _castu32_f32(w); +#else + return c10::bit_cast(w); +#endif +} + +C10_HOST_DEVICE inline uint32_t fp32_to_bits(float f) { +#if defined(__OPENCL_VERSION__) + return as_uint(f); +#elif defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__) + return (uint32_t)__float_as_uint(f); +#elif defined(__INTEL_COMPILER) + return _castf32_u32(f); +#else + return c10::bit_cast(f); +#endif +} + +} // namespace c10::detail diff --git a/third-party/include/c10/util/irange.h b/third-party/include/c10/util/irange.h new file mode 100644 index 0000000000..72a748cb0e --- /dev/null +++ b/third-party/include/c10/util/irange.h @@ -0,0 +1,107 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include +#include + +namespace c10 { + +namespace detail { + +template , int> = 0> +struct integer_iterator { + using iterator_category = std::input_iterator_tag; + using value_type = I; + using difference_type = std::ptrdiff_t; + using pointer = I *; + using reference = I &; + + explicit constexpr integer_iterator(I value_) : value(value_) {} + + constexpr I operator*() const { return value; } + + constexpr I const *operator->() const { return &value; } + + constexpr integer_iterator &operator++() { + ++value; + return *this; + } + + constexpr integer_iterator operator++(int) { + const auto copy = *this; + ++*this; + return copy; + } + + constexpr bool operator==(const integer_iterator &other) const { + if constexpr (one_sided) { + // Range-for loops' end test is `begin != end`, not `begin < + // end`. To handle `c10::irange(n)` where n < 0 (which should be + // empty), we just make `begin != end` fail whenever `end` is + // negative. + return is_negative(other.value) || value == other.value; + } else { + return value == other.value; + } + // Suppress "warning: missing return statement at end of non-void function" + // which Nvidia's Robert Crovella confirms is an NVCC compiler error + // here https://stackoverflow.com/a/64561686/752843 on 2020-10-27 + // `__builtin_unreachable();` would be best here, but it's not + // available with all compilers. So we instead return an arbitrary + // value trusting that this line will, in fact, never be reached. + return false; // Horrible hack + } + + constexpr bool operator!=(const integer_iterator &other) const { + return !(*this == other); + } + +protected: + I value; +}; + +} // namespace detail + +template , bool> = true> +struct integer_range { +public: + constexpr integer_range(I begin, I end) : begin_(begin), end_(end) {} + using iterator = detail::integer_iterator; + constexpr iterator begin() const { return begin_; } + constexpr iterator end() const { return end_; } + +private: + iterator begin_; + iterator end_; +}; + +/// Creates an integer range for the half-open interval [begin, end) +/// If end<=begin, then the range is empty. +/// The range has the type of the `end` integer; `begin` integer is +/// cast to this type. +template , bool> = true, + std::enable_if_t, bool> = true> +integer_range irange(Integer1 begin, Integer2 end) { + // If end<=begin then the range is empty; we can achieve this effect by + // choosing the larger of {begin, end} as the loop terminator + return {static_cast(begin), + std::max(static_cast(begin), end)}; +} + +/// Creates an integer range for the half-open interval [0, end) +/// If end<=begin, then the range is empty +template , bool> = true> +constexpr integer_range irange(Integer end) { + return {Integer(), end}; +} + +} // namespace c10 diff --git a/third-party/include/executorch/ExecuTorch.h b/third-party/include/executorch/ExecuTorch.h index e16439714f..3a12a5ddba 100644 --- a/third-party/include/executorch/ExecuTorch.h +++ b/third-party/include/executorch/ExecuTorch.h @@ -6,4 +6,8 @@ * LICENSE file in the root directory of this source tree. */ +#import "ExecuTorchError.h" #import "ExecuTorchLog.h" +#import "ExecuTorchModule.h" +#import "ExecuTorchTensor.h" +#import "ExecuTorchValue.h" diff --git a/third-party/include/executorch/ExecuTorchError.h b/third-party/include/executorch/ExecuTorchError.h new file mode 100644 index 0000000000..618c7fc8b0 --- /dev/null +++ b/third-party/include/executorch/ExecuTorchError.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSErrorDomain const + ExecuTorchErrorDomain NS_SWIFT_NAME(ErrorDomain); + +NS_ASSUME_NONNULL_END diff --git a/third-party/include/executorch/ExecuTorchModule.h b/third-party/include/executorch/ExecuTorchModule.h new file mode 100644 index 0000000000..b581f68b51 --- /dev/null +++ b/third-party/include/executorch/ExecuTorchModule.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "ExecuTorchValue.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Enum to define loading behavior. + * Values can be a subset, but must numerically match exactly those defined in + * extension/module/module.h + */ +typedef NS_ENUM(NSInteger, ExecuTorchModuleLoadMode) { + ExecuTorchModuleLoadModeFile = 0, + ExecuTorchModuleLoadModeMmap, + ExecuTorchModuleLoadModeMmapUseMlock, + ExecuTorchModuleLoadModeMmapUseMlockIgnoreErrors, +} NS_SWIFT_NAME(ModuleLoadMode); + +/** + * Enum to define the verification level used when loading a module. + * Values can be a subset, but must numerically match exactly those defined in + * runtime/executor/program.h + */ +typedef NS_ENUM(uint8_t, ExecuTorchVerification) { + ExecuTorchVerificationMinimal, + ExecuTorchVerificationInternalConsistency, +} NS_SWIFT_NAME(ModuleVerification); + +/** + * Represents a module that encapsulates an ExecuTorch program. + * This class is a facade for loading programs and executing methods within + * them. + */ +NS_SWIFT_NAME(Module) +__attribute__((deprecated("This API is experimental."))) +@interface ExecuTorchModule : NSObject + +/** + * Initializes a module with a file path and a specified load mode. + * + * @param filePath A string representing the path to the ExecuTorch program + * file. + * @param loadMode A value from ExecuTorchModuleLoadMode that determines the + * file loading behavior. + * @return An initialized ExecuTorchModule instance. + */ +- (instancetype)initWithFilePath:(NSString *)filePath + loadMode:(ExecuTorchModuleLoadMode)loadMode + NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a module with a file path using the default load mode (File + * mode). + * + * @param filePath A string representing the path to the ExecuTorch program + * file. + * @return An initialized ExecuTorchModule instance. + */ +- (instancetype)initWithFilePath:(NSString *)filePath; + +/** + * Loads the module’s program using the specified verification level. + * + * @param verification The verification level to apply when loading the program. + * @param error A pointer to an NSError pointer that will be set if an error + * occurs. + * @return YES if the program was successfully loaded; otherwise, NO. + */ +- (BOOL)loadWithVerification:(ExecuTorchVerification)verification + error:(NSError **)error; + +/** + * Loads the module’s program using minimal verification. + * + * This is a convenience overload that defaults the verification level to + * Minimal. + * + * @param error A pointer to an NSError pointer that will be set if an error + * occurs. + * @return YES if the program was successfully loaded; otherwise, NO. + */ +- (BOOL)load:(NSError **)error; + +/** + * Checks if the module is loaded. + * + * @return YES if the module's program is loaded; otherwise, NO. + */ +- (BOOL)isLoaded; + +/** + * Loads a specific method from the program. + * + * @param methodName A string representing the name of the method to load. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return YES if the method was successfully loaded; otherwise, NO. + */ +- (BOOL)loadMethod:(NSString *)methodName + error:(NSError **)error NS_SWIFT_NAME(load(_:)); + +/** + * Checks if a specific method is loaded. + * + * @param methodName A string representing the method name. + * @return YES if the method is loaded; otherwise, NO. + */ +- (BOOL)isMethodLoaded:(NSString *)methodName NS_SWIFT_NAME(isLoaded(_:)); + +/** + * Retrieves the set of method names available in the loaded program. + * + * The method names are returned as an unordered set of strings. The program and + * methods are loaded as needed. + * + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An unordered set of method names, or nil in case of an error. + */ +- (nullable NSSet *)methodNames:(NSError **)error; + +/** + * Executes a specific method with the provided input values. + * + * The method is loaded on demand if not already loaded. + * + * @param methodName A string representing the method name. + * @param values An NSArray of ExecuTorchValue objects representing the inputs. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *) + executeMethod:(NSString *)methodName + withInputs:(NSArray *)values + error:(NSError **)error NS_SWIFT_NAME(execute(_:_:)); + +/** + * Executes a specific method with the provided single input value. + * + * The method is loaded on demand if not already loaded. + * + * @param methodName A string representing the method name. + * @param value An ExecuTorchValue object representing the input. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *)executeMethod:(NSString *)methodName + withInput:(ExecuTorchValue *)value + error:(NSError **)error + NS_SWIFT_NAME(execute(_:_:)); + +/** + * Executes a specific method with no input values. + * + * The method is loaded on demand if not already loaded. + * + * @param methodName A string representing the method name. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *)executeMethod:(NSString *)methodName + error:(NSError **)error + NS_SWIFT_NAME(execute(_:)); + +/** + * Executes a specific method with the provided input tensors. + * + * The method is loaded on demand if not already loaded. + * + * @param methodName A string representing the method name. + * @param tensors An NSArray of ExecuTorchTensor objects representing the + * inputs. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *) + executeMethod:(NSString *)methodName + withTensors:(NSArray *)tensors + error:(NSError **)error NS_SWIFT_NAME(execute(_:_:)); + +/** + * Executes a specific method with the provided single input tensor. + * + * The method is loaded on demand if not already loaded. + * + * @param methodName A string representing the method name. + * @param tensor An ExecuTorchTensor object representing the input. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *)executeMethod:(NSString *)methodName + withTensor: + (ExecuTorchTensor *)tensor + error:(NSError **)error + NS_SWIFT_NAME(execute(_:_:)); + +/** + * Executes the "forward" method with the provided input values. + * + * This is a convenience method that calls the executeMethod with "forward" as + * the method name. + * + * @param values An NSArray of ExecuTorchValue objects representing the inputs. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *) + forwardWithInputs:(NSArray *)values + error:(NSError **)error NS_SWIFT_NAME(forward(_:)); + +/** + * Executes the "forward" method with the provided single input value. + * + * This is a convenience method that calls the executeMethod with "forward" as + * the method name. + * + * @param value An ExecuTorchValue object representing the input. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *)forwardWithInput: + (ExecuTorchValue *)value + error:(NSError **)error + NS_SWIFT_NAME(forward(_:)); + +/** + * Executes the "forward" method with no inputs. + * + * This is a convenience method that calls the executeMethod with "forward" as + * the method name. + * + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *)forward:(NSError **)error; + +/** + * Executes the "forward" method with the provided input tensors. + * + * This is a convenience method that calls the executeMethod with "forward" as + * the method name. + * + * @param tensors An NSArray of ExecuTorchTensor objects representing the + * inputs. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *) + forwardWithTensors:(NSArray *)tensors + error:(NSError **)error NS_SWIFT_NAME(forward(_:)); + +/** + * Executes the "forward" method with the provided single input tensor. + * + * This is a convenience method that calls the executeMethod with "forward" as + * the method name. + * + * @param tensor An ExecuTorchTensor object representing the input. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return An NSArray of ExecuTorchValue objects representing the outputs, or + * nil in case of an error. + */ +- (nullable NSArray *)forwardWithTensor: + (ExecuTorchTensor *)tensor + error:(NSError **)error + NS_SWIFT_NAME(forward(_:)); + ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/third-party/include/executorch/ExecuTorchTensor.h b/third-party/include/executorch/ExecuTorchTensor.h new file mode 100644 index 0000000000..1f44baeeea --- /dev/null +++ b/third-party/include/executorch/ExecuTorchTensor.h @@ -0,0 +1,742 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Enum to define the data type of a Tensor. + * Values can be a subset, but must numerically match exactly those defined in + * runtime/core/portable_type/scalar_type.h + */ +typedef NS_ENUM(int8_t, ExecuTorchDataType) { + ExecuTorchDataTypeByte, + ExecuTorchDataTypeChar, + ExecuTorchDataTypeShort, + ExecuTorchDataTypeInt, + ExecuTorchDataTypeLong, + ExecuTorchDataTypeHalf, + ExecuTorchDataTypeFloat, + ExecuTorchDataTypeDouble, + ExecuTorchDataTypeComplexHalf, + ExecuTorchDataTypeComplexFloat, + ExecuTorchDataTypeComplexDouble, + ExecuTorchDataTypeBool, + ExecuTorchDataTypeQInt8, + ExecuTorchDataTypeQUInt8, + ExecuTorchDataTypeQInt32, + ExecuTorchDataTypeBFloat16, + ExecuTorchDataTypeQUInt4x2, + ExecuTorchDataTypeQUInt2x4, + ExecuTorchDataTypeBits1x8, + ExecuTorchDataTypeBits2x4, + ExecuTorchDataTypeBits4x2, + ExecuTorchDataTypeBits8, + ExecuTorchDataTypeBits16, + ExecuTorchDataTypeFloat8_e5m2, + ExecuTorchDataTypeFloat8_e4m3fn, + ExecuTorchDataTypeFloat8_e5m2fnuz, + ExecuTorchDataTypeFloat8_e4m3fnuz, + ExecuTorchDataTypeUInt16, + ExecuTorchDataTypeUInt32, + ExecuTorchDataTypeUInt64, + ExecuTorchDataTypeUndefined, + ExecuTorchDataTypeNumOptions, +} NS_SWIFT_NAME(DataType); + +/** + * Enum to define the shape dynamism of a Tensor. + * Values can be a subset, but must numerically match exactly those defined in + * runtime/core/tensor_shape_dynamism.h + */ +typedef NS_ENUM(uint8_t, ExecuTorchShapeDynamism) { + ExecuTorchShapeDynamismStatic, + ExecuTorchShapeDynamismDynamicBound, + ExecuTorchShapeDynamismDynamicUnbound, +} NS_SWIFT_NAME(ShapeDynamism); + +/** + * Returns the size in bytes of the specified data type. + * + * @param dataType An ExecuTorchDataType value representing the tensor's element + * type. + * @return An NSInteger indicating the size in bytes. + */ +FOUNDATION_EXPORT +__attribute__((deprecated("This API is experimental."))) NSInteger +ExecuTorchSizeOfDataType(ExecuTorchDataType dataType) + NS_SWIFT_NAME(size(ofDataType:)); + +/** + * Computes the total number of elements in a tensor based on its shape. + * + * @param shape An NSArray of NSNumber objects, where each element represents a + * dimension size. + * @return An NSInteger equal to the product of the sizes of all dimensions. + */ +FOUNDATION_EXPORT +__attribute__((deprecated("This API is experimental."))) NSInteger +ExecuTorchElementCountOfShape(NSArray *shape) + NS_SWIFT_NAME(elementCount(ofShape:)); + +/** + * A tensor class for ExecuTorch operations. + * + * This class encapsulates a native TensorPtr instance and provides a variety of + * initializers and utility methods to work with tensor data. + */ +NS_SWIFT_NAME(Tensor) +__attribute__((deprecated("This API is experimental."))) +@interface ExecuTorchTensor : NSObject + +/** + * Pointer to the underlying native TensorPtr instance. + * + * @return A raw pointer to the native TensorPtr held by this Tensor class. + */ +@property(nonatomic, readonly) void *nativeInstance NS_SWIFT_UNAVAILABLE(""); + +/** + * The data type of the tensor. + * + * @return An ExecuTorchDataType value representing the tensor's element type. + */ +@property(nonatomic, readonly) ExecuTorchDataType dataType; + +/** + * The shape of the tensor. + * + * @return An NSArray of NSNumber objects representing the size of each + * dimension. + */ +@property(nonatomic, readonly) NSArray *shape; + +/** + * The order of dimensions in the tensor. + * + * @return An NSArray of NSNumber objects representing the tensor’s dimension + * order. + */ +@property(nonatomic, readonly) NSArray *dimensionOrder; + +/** + * The strides of the tensor. + * + * @return An NSArray of NSNumber objects representing the step sizes for each + * dimension. + */ +@property(nonatomic, readonly) NSArray *strides; + +/** + * The dynamism of the tensor's shape. + * + * @return An ExecuTorchShapeDynamism value indicating whether the tensor shape + * is static or dynamic. + */ +@property(nonatomic, readonly) ExecuTorchShapeDynamism shapeDynamism; + +/** + * The total number of elements in the tensor. + * + * @return An NSInteger representing the total element count. + */ +@property(nonatomic, readonly) NSInteger count; + +/** + * Initializes a tensor with a native TensorPtr instance. + * + * @param nativeInstance A pointer to a native TensorPtr instance. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithNativeInstance:(void *)nativeInstance + NS_DESIGNATED_INITIALIZER NS_SWIFT_UNAVAILABLE(""); + +/** + * Creates a new tensor by copying an existing tensor. + * + * @param otherTensor The tensor instance to copy. + * @return A new ExecuTorchTensor instance that is a copy of otherTensor. + */ +- (instancetype)initWithTensor:(ExecuTorchTensor *)otherTensor + NS_SWIFT_NAME(init(_:)); + +/** + * Returns a copy of the tensor. + * + * @return A new ExecuTorchTensor instance that is a duplicate of the current + * tensor. + */ +- (instancetype)copy; + +/** + * Executes a block with a pointer to the tensor's immutable byte data. + * + * @param handler A block that receives: + * - a pointer to the data, + * - the total number of elements, + * - and the data type. + */ +- (void)bytesWithHandler:(void (^)(const void *pointer, NSInteger count, + ExecuTorchDataType dataType))handler + NS_SWIFT_NAME(bytes(_:)); + +/** + * Executes a block with a pointer to the tensor's mutable byte data. + * + * @param handler A block that receives: + * - a mutable pointer to the data, + * - the total number of elements, + * - and the data type. + */ +- (void)mutableBytesWithHandler:(void (^)(void *pointer, NSInteger count, + ExecuTorchDataType dataType))handler + NS_SWIFT_NAME(mutableBytes(_:)); + +/** + * Resizes the tensor to a new shape. + * + * @param shape An NSArray of NSNumber objects representing the desired new + * shape. + * @param error A pointer to an NSError pointer that is set if an error occurs. + * @return YES if the tensor was successfully resized; otherwise, NO. + */ +- (BOOL)resizeToShape:(NSArray *)shape + error:(NSError **)error NS_SWIFT_NAME(resize(to:)); + +/** + * Determines whether the current tensor is equal to another tensor. + * + * @param other Another ExecuTorchTensor instance to compare against. + * @return YES if the tensors have the same type, shape, strides, and data; + * otherwise, NO. + */ +- (BOOL)isEqualToTensor:(nullable ExecuTorchTensor *)other; + ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; + +@end + +#pragma mark - BytesNoCopy Category + +@interface ExecuTorchTensor (BytesNoCopy) + +/** + * Initializes a tensor without copying the provided data. + * + * @param pointer A pointer to the data buffer. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param strides An NSArray of NSNumber objects representing the tensor's + * strides. + * @param dimensionOrder An NSArray of NSNumber objects indicating the order of + * dimensions. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating whether the + * shape is static or dynamic. + * @return An initialized ExecuTorchTensor instance using the provided data + * buffer. + */ +- (instancetype)initWithBytesNoCopy:(void *)pointer + shape:(NSArray *)shape + strides:(NSArray *)strides + dimensionOrder:(NSArray *)dimensionOrder + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism; + +/** + * Initializes a tensor without copying data using dynamic bound shape (default + * strides and dimension order). + * + * @param pointer A pointer to the data buffer. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param strides An NSArray of NSNumber objects representing the tensor's + * strides. + * @param dimensionOrder An NSArray of NSNumber objects indicating the order of + * dimensions. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithBytesNoCopy:(void *)pointer + shape:(NSArray *)shape + strides:(NSArray *)strides + dimensionOrder:(NSArray *)dimensionOrder + dataType:(ExecuTorchDataType)dataType; + +/** + * Initializes a tensor without copying data, with an explicit shape dynamism. + * + * @param pointer A pointer to the data buffer. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithBytesNoCopy:(void *)pointer + shape:(NSArray *)shape + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism; + +/** + * Initializes a tensor without copying data, specifying only the shape and data + * type. + * + * @param pointer A pointer to the data buffer. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithBytesNoCopy:(void *)pointer + shape:(NSArray *)shape + dataType:(ExecuTorchDataType)dataType; + +@end + +#pragma mark - Bytes Category + +@interface ExecuTorchTensor (Bytes) + +/** + * Initializes a tensor by copying bytes from the provided pointer. + * + * @param pointer A pointer to the source data buffer. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param strides An NSArray of NSNumber objects representing the tensor's + * strides. + * @param dimensionOrder An NSArray of NSNumber objects indicating the order of + * dimensions. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance with its own copy of the + * data. + */ +- (instancetype)initWithBytes:(const void *)pointer + shape:(NSArray *)shape + strides:(NSArray *)strides + dimensionOrder:(NSArray *)dimensionOrder + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism; + +/** + * Initializes a tensor by copying bytes from the provided pointer with dynamic + * bound shape. + * + * @param pointer A pointer to the source data buffer. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param strides An NSArray of NSNumber objects representing the tensor's + * strides. + * @param dimensionOrder An NSArray of NSNumber objects indicating the order of + * dimensions. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance with its own copy of the + * data. + */ +- (instancetype)initWithBytes:(const void *)pointer + shape:(NSArray *)shape + strides:(NSArray *)strides + dimensionOrder:(NSArray *)dimensionOrder + dataType:(ExecuTorchDataType)dataType; + +/** + * Initializes a tensor by copying bytes from the provided pointer, specifying + * shape, data type, and explicit shape dynamism. + * + * @param pointer A pointer to the source data buffer. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance with its own copy of the + * data. + */ +- (instancetype)initWithBytes:(const void *)pointer + shape:(NSArray *)shape + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism; + +/** + * Initializes a tensor by copying bytes from the provided pointer, specifying + * only the shape and data type. + * + * @param pointer A pointer to the source data buffer. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance with its own copy of the + * data. + */ +- (instancetype)initWithBytes:(const void *)pointer + shape:(NSArray *)shape + dataType:(ExecuTorchDataType)dataType; + +@end + +#pragma mark - Data Category + +@interface ExecuTorchTensor (Data) + +/** + * Initializes a tensor using an NSData object as the underlying data buffer. + * + * @param data An NSData object containing the tensor data. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param strides An NSArray of NSNumber objects representing the tensor's + * strides. + * @param dimensionOrder An NSArray of NSNumber objects indicating the order of + * dimensions. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance using the provided data. + */ +- (instancetype)initWithData:(NSData *)data + shape:(NSArray *)shape + strides:(NSArray *)strides + dimensionOrder:(NSArray *)dimensionOrder + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism; + +/** + * Initializes a tensor using an NSData object as the underlying data buffer + * with dynamic bound shape. + * + * @param data An NSData object containing the tensor data. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param strides An NSArray of NSNumber objects representing the tensor's + * strides. + * @param dimensionOrder An NSArray of NSNumber objects indicating the order of + * dimensions. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance using the provided data. + */ +- (instancetype)initWithData:(NSData *)data + shape:(NSArray *)shape + strides:(NSArray *)strides + dimensionOrder:(NSArray *)dimensionOrder + dataType:(ExecuTorchDataType)dataType; + +/** + * Initializes a tensor using an NSData object as the underlying data buffer, + * specifying shape, data type, and explicit shape dynamism. + * + * @param data An NSData object containing the tensor data. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance using the provided data. + */ +- (instancetype)initWithData:(NSData *)data + shape:(NSArray *)shape + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism; + +/** + * Initializes a tensor using an NSData object as the underlying data buffer, + * specifying only the shape and data type. + * + * @param data An NSData object containing the tensor data. + * @param shape An NSArray of NSNumber objects representing the tensor's shape. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance using the provided data. + */ +- (instancetype)initWithData:(NSData *)data + shape:(NSArray *)shape + dataType:(ExecuTorchDataType)dataType; + +@end + +#pragma mark - Scalars Category + +@interface ExecuTorchTensor (Scalars) + +/** + * Initializes a tensor with an array of scalar values and full tensor + * properties. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @param shape An NSArray of NSNumber objects representing the desired tensor + * shape. + * @param strides An NSArray of NSNumber objects representing the tensor + * strides. + * @param dimensionOrder An NSArray of NSNumber objects indicating the order of + * dimensions. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance containing the provided + * scalar values. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + shape:(NSArray *)shape + strides:(NSArray *)strides + dimensionOrder:(NSArray *)dimensionOrder + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism + NS_SWIFT_NAME(init(_:shape:strides:dimensionOrder:dataType:shapeDynamism:)); + +/** + * Initializes a tensor with an array of scalar values, specifying shape, + * strides, dimension order, and data type, using a default dynamic bound shape + * for shape dynamism. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @param shape An NSArray of NSNumber objects representing the desired tensor + * shape. + * @param strides An NSArray of NSNumber objects representing the tensor + * strides. + * @param dimensionOrder An NSArray of NSNumber objects indicating the order of + * dimensions. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance containing the scalar + * values. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + shape:(NSArray *)shape + strides:(NSArray *)strides + dimensionOrder:(NSArray *)dimensionOrder + dataType:(ExecuTorchDataType)dataType + NS_SWIFT_NAME(init(_:shape:strides:dimensionOrder:dataType:)); + +/** + * Initializes a tensor with an array of scalar values, specifying the desired + * shape, data type, and explicit shape dynamism. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @param shape An NSArray of NSNumber objects representing the desired tensor + * shape. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + shape:(NSArray *)shape + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism + NS_SWIFT_NAME(init(_:shape:dataType:shapeDynamism:)); + +/** + * Initializes a tensor with an array of scalar values and a specified shape, + * using a default dynamic bound shape for shape dynamism. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @param shape An NSArray of NSNumber objects representing the desired tensor + * shape. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + shape:(NSArray *)shape + dataType:(ExecuTorchDataType)dataType + NS_SWIFT_NAME(init(_:shape:dataType:)); + +/** + * Initializes a tensor with an array of scalar values, specifying the tensor + * data type and explicit shape dynamism. The shape is deduced from the count of + * the scalar array. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance with the shape deduced from + * the scalar count. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + dataType:(ExecuTorchDataType)dataType + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism + NS_SWIFT_NAME(init(_:dataType:shapeDynamism:)); + +/** + * Initializes a tensor with an array of scalar values, specifying the tensor + * data type. The shape is deduced from the count of the scalar array. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance with the shape deduced from + * the scalar count. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + dataType:(ExecuTorchDataType)dataType + NS_SWIFT_NAME(init(_:dataType:)); + +/** + * Initializes a tensor with an array of scalar values, a specified shape and + * explicit shape dynamism. The data type is automatically deduced from the + * first element of the array. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @param shape An NSArray of NSNumber objects representing the desired tensor + * shape. + * @param shapeDynamism An ExecuTorchShapeDynamism value indicating the shape + * dynamism. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + shape:(NSArray *)shape + shapeDynamism:(ExecuTorchShapeDynamism)shapeDynamism + NS_SWIFT_NAME(init(_:shape:shapeDynamism:)); + +/** + * Initializes a tensor with an array of scalar values and a specified shape. + * The data type is automatically deduced from the first element of the array. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @param shape An NSArray of NSNumber objects representing the desired tensor + * shape. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + shape:(NSArray *)shape + NS_SWIFT_NAME(init(_:shape:)); + +/** + * Initializes a tensor with an array of scalar values, automatically deducing + * the tensor shape and data type. + * + * @param scalars An NSArray of NSNumber objects representing the scalar values. + * @return An initialized ExecuTorchTensor instance with shape and data type + * deduced. + */ +- (instancetype)initWithScalars:(NSArray *)scalars + NS_SWIFT_NAME(init(_:)); + +@end + +@interface ExecuTorchTensor (Scalar) + +/** + * Initializes a tensor with a single scalar value and a specified data type. + * + * @param scalar An NSNumber representing the scalar value. + * @param dataType An ExecuTorchDataType value specifying the element type. + * @return An initialized ExecuTorchTensor instance representing the scalar. + */ +- (instancetype)initWithScalar:(NSNumber *)scalar + dataType:(ExecuTorchDataType)dataType + NS_SWIFT_NAME(init(_:dataType:)); + +/** + * Initializes a tensor with a single scalar value, automatically deducing its + * data type. + * + * @param scalar An NSNumber representing the scalar value. + * @return An initialized ExecuTorchTensor instance representing the scalar. + */ +- (instancetype)initWithScalar:(NSNumber *)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a byte scalar value. + * + * @param scalar A uint8_t value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithByte:(uint8_t)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a char scalar value. + * + * @param scalar An int8_t value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithChar:(int8_t)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a short scalar value. + * + * @param scalar An int16_t value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithShort:(int16_t)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with an int scalar value. + * + * @param scalar An int32_t value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithInt:(int32_t)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a long scalar value. + * + * @param scalar An int64_t value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithLong:(int64_t)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a float scalar value. + * + * @param scalar A float value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithFloat:(float)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a double scalar value. + * + * @param scalar A double value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithDouble:(double)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a boolean scalar value. + * + * @param scalar A BOOL value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithBool:(BOOL)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a uint16 scalar value. + * + * @param scalar A uint16_t value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithUInt16:(uint16_t)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a uint32 scalar value. + * + * @param scalar A uint32_t value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithUInt32:(uint32_t)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with a uint64 scalar value. + * + * @param scalar A uint64_t value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithUInt64:(uint64_t)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with an NSInteger scalar value. + * + * @param scalar An NSInteger value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithInteger:(NSInteger)scalar NS_SWIFT_NAME(init(_:)); + +/** + * Initializes a tensor with an NSUInteger scalar value. + * + * @param scalar An NSUInteger value. + * @return An initialized ExecuTorchTensor instance. + */ +- (instancetype)initWithUnsignedInteger:(NSUInteger)scalar + NS_SWIFT_NAME(init(_:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/third-party/include/executorch/ExecuTorchValue.h b/third-party/include/executorch/ExecuTorchValue.h new file mode 100644 index 0000000000..d4e8511048 --- /dev/null +++ b/third-party/include/executorch/ExecuTorchValue.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "ExecuTorchTensor.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Enum to define the dynamic type of a Value. + * Values can be a subset, but must numerically match exactly those defined in + * runtime/core/tag.h + */ +typedef NS_ENUM(uint32_t, ExecuTorchValueTag) { + ExecuTorchValueTagNone, + ExecuTorchValueTagTensor, + ExecuTorchValueTagString, + ExecuTorchValueTagDouble, + ExecuTorchValueTagInteger, + ExecuTorchValueTagBoolean, + ExecuTorchValueTagBooleanList, + ExecuTorchValueTagDoubleList, + ExecuTorchValueTagIntegerList, + ExecuTorchValueTagTensorList, + ExecuTorchValueTagScalarList, + ExecuTorchValueTagOptionalTensorList, +} NS_SWIFT_NAME(ValueTag); + +typedef NSNumber * + ExecuTorchScalarValue NS_SWIFT_BRIDGED_TYPEDEF NS_SWIFT_NAME(ScalarValue); +typedef NSString * + ExecuTorchStringValue NS_SWIFT_BRIDGED_TYPEDEF NS_SWIFT_NAME(StringValue); +typedef BOOL + ExecuTorchBooleanValue NS_SWIFT_BRIDGED_TYPEDEF NS_SWIFT_NAME(BoolValue); +typedef NSInteger + ExecuTorchIntegerValue NS_SWIFT_BRIDGED_TYPEDEF NS_SWIFT_NAME(IntegerValue); +typedef double + ExecuTorchDoubleValue NS_SWIFT_BRIDGED_TYPEDEF NS_SWIFT_NAME(DoubleValue); + +/** + * A dynamic value type used by ExecuTorch. + * + * ExecuTorchValue encapsulates a value that may be of various types such as + * a tensor or a scalar. The value’s type is indicated by its tag. + */ +NS_SWIFT_NAME(Value) +__attribute__((deprecated("This API is experimental."))) +@interface ExecuTorchValue : NSObject + +/** + * The tag that indicates the dynamic type of the value. + * + * @return An ExecuTorchValueTag value. + */ +@property(nonatomic, readonly) ExecuTorchValueTag tag; + +/** + * The tensor value if the tag is ExecuTorchValueTagTensor. + * + * @return A Tensor instance or nil. + */ +@property(nullable, nonatomic, readonly) + ExecuTorchTensor *tensorValue NS_SWIFT_NAME(tensor); + +/** + * The string value if the tag is ExecuTorchValueTagString. + * + * @return An NSString instance or nil. + */ +@property(nullable, nonatomic, readonly) + ExecuTorchStringValue stringValue NS_SWIFT_NAME(string); + +/** + * The scalar value if the tag is boolean, integer or double. + * + * @return A scalar value or nil. + */ +@property(nullable, nonatomic, readonly) + ExecuTorchScalarValue scalarValue NS_SWIFT_NAME(scalar); + +/** + * The boolean value if the tag is ExecuTorchValueTagBoolean. + * + * @return A BOOL representing the boolean value. + */ +@property(nonatomic, readonly) + ExecuTorchBooleanValue boolValue NS_SWIFT_NAME(boolean); + +/** + * The integer value if the tag is ExecuTorchValueTagInteger. + * + * @return An NSInteger representing the integer value. + */ +@property(nonatomic, readonly) + ExecuTorchIntegerValue intValue NS_SWIFT_NAME(integer); + +/** + * The double value if the tag is ExecuTorchValueTagDouble. + * + * @return A double representing the double value. + */ +@property(nonatomic, readonly) + ExecuTorchDoubleValue doubleValue NS_SWIFT_NAME(double); + +/** + * Returns YES if the value is of type None. + * + * @return A BOOL indicating whether the value is None. + */ +@property(nonatomic, readonly) BOOL isNone; + +/** + * Returns YES if the value is a Tensor. + * + * @return A BOOL indicating whether the value is a Tensor. + */ +@property(nonatomic, readonly) BOOL isTensor; + +/** + * Returns YES if the value is a string. + * + * @return A BOOL indicating whether the value is a string. + */ +@property(nonatomic, readonly) BOOL isString; + +/** + * Returns YES if the value is a scalar (boolean, integer or double). + * + * @return A BOOL indicating whether the value is a scalar. + */ +@property(nonatomic, readonly) BOOL isScalar; + +/** + * Returns YES if the value is a boolean. + * + * @return A BOOL indicating whether the value is a boolean. + */ +@property(nonatomic, readonly) BOOL isBoolean; + +/** + * Returns YES if the value is an integer. + * + * @return A BOOL indicating whether the value is an integer. + */ +@property(nonatomic, readonly) BOOL isInteger; + +/** + * Returns YES if the value is a double. + * + * @return A BOOL indicating whether the value is a double. + */ +@property(nonatomic, readonly) BOOL isDouble; + +/** + * Creates an instance encapsulating a Tensor. + * + * @param value An ExecuTorchTensor instance. + * @return A new ExecuTorchValue instance with a tag of + * ExecuTorchValueTagTensor. + */ ++ (instancetype)valueWithTensor:(ExecuTorchTensor *)value + NS_SWIFT_NAME(init(_:)); + +/** + * Creates an instance encapsulating a string. + * + * @param value A string. + * @return A new ExecuTorchValue instance with a tag of + * ExecuTorchValueTagString. + */ ++ (instancetype)valueWithString:(ExecuTorchStringValue)value + NS_SWIFT_NAME(init(_:)); + +/** + * Creates an instance encapsulating a boolean. + * + * @param value A boolean. + * @return A new ExecuTorchValue instance with a tag of + * ExecuTorchValueTagBoolean. + */ ++ (instancetype)valueWithBoolean:(ExecuTorchBooleanValue)value + NS_SWIFT_NAME(init(_:)); + +/** + * Creates an instance encapsulating an integer. + * + * @param value An integer. + * @return A new ExecuTorchValue instance with a tag of + * ExecuTorchValueTagInteger. + */ ++ (instancetype)valueWithInteger:(ExecuTorchIntegerValue)value + NS_SWIFT_NAME(init(_:)); + +/** + * Creates an instance encapsulating a double value. + * + * @param value A double value. + * @return A new ExecuTorchValue instance with a tag of + * ExecuTorchValueTagDouble. + */ ++ (instancetype)valueWithDouble:(ExecuTorchDoubleValue)value + NS_SWIFT_NAME(init(_:)); + +/** + * Determines whether the current Value is equal to another Value. + * + * @param other Another ExecuTorchValue instance to compare against. + * @return YES if the values have the same tag and equal underlying values; + * otherwise, NO. + */ +- (BOOL)isEqualToValue:(nullable ExecuTorchValue *)other; + +@end + +NS_ASSUME_NONNULL_END diff --git a/third-party/include/executorch/extension/module/module.h b/third-party/include/executorch/extension/module/module.h index 5fb2723c79..1e7755fa78 100644 --- a/third-party/include/executorch/extension/module/module.h +++ b/third-party/include/executorch/extension/module/module.h @@ -50,6 +50,20 @@ class Module { const LoadMode load_mode = LoadMode::MmapUseMlock, std::unique_ptr event_tracer = nullptr); + /** + * Constructs an instance by loading a program from a file with specified + * memory locking behavior. + * + * @param[in] file_path The path to the ExecuTorch program file to load. + * @param[in] data_map_path The path to a .ptd file + * @param[in] load_mode The loading mode to use. + * @param[in] event_tracer A EventTracer used for tracking and logging events. + */ + explicit Module(const std::string &file_path, + const std::string &data_map_path, + const LoadMode load_mode = LoadMode::MmapUseMlock, + std::unique_ptr event_tracer = nullptr); + /** * Constructs an instance with the provided data loader and memory allocator. * @@ -58,12 +72,14 @@ class Module { * @param[in] temp_allocator A MemoryAllocator to use when allocating * temporary data during kernel or delegate execution. * @param[in] event_tracer A EventTracer used for tracking and logging events. + * @param[in] data_map_loader A DataLoader used for loading external weights. */ explicit Module( std::unique_ptr data_loader, std::unique_ptr memory_allocator = nullptr, std::unique_ptr temp_allocator = nullptr, - std::unique_ptr event_tracer = nullptr); + std::unique_ptr event_tracer = nullptr, + std::unique_ptr data_map_loader = nullptr); /** * Constructs an instance using an existing shared program. @@ -74,12 +90,14 @@ class Module { * @param[in] temp_allocator A MemoryAllocator to use when allocating * temporary data. * @param[in] event_tracer A EventTracer used for tracking and logging events. + * @param[in] data_map_loader A DataLoader used for loading external weights. */ explicit Module( std::shared_ptr program, std::unique_ptr memory_allocator = nullptr, std::unique_ptr temp_allocator = nullptr, - std::unique_ptr event_tracer = nullptr); + std::unique_ptr event_tracer = nullptr, + std::unique_ptr data_map_loader = nullptr); Module(const Module &) = delete; Module &operator=(const Module &) = delete; @@ -113,6 +131,14 @@ class Module { */ inline std::shared_ptr program() const { return program_; } + /** + * Get the number of methods available in the loaded program. + * + * @returns A Result object containing either the number of methods available + * or an error to indicate failure. + */ + runtime::Result num_methods(); + /** * Get a list of method names available in the loaded program. * Loads the program and method if needed. @@ -127,6 +153,8 @@ class Module { * needed. The loaded method is cached to reuse the next time it's executed. * * @param[in] method_name The name of the method to load. + * @param[in] planned_memory The memory-planned buffers to use for mutable + * tensor data when executing a method. * @param[in] event_tracer Per-method event tracer to profile/trace methods * individually. When not given, the event tracer passed to the Module * constructor is used. Otherwise, this per-method event tracer takes @@ -137,20 +165,35 @@ class Module { ET_NODISCARD runtime::Error load_method(const std::string &method_name, + runtime::HierarchicalAllocator *planned_memory = nullptr, torch::executor::EventTracer *event_tracer = nullptr); + ET_DEPRECATED ET_NODISCARD runtime::Error inline load_method( + const std::string &method_name, + torch::executor::EventTracer *event_tracer) { + return load_method(method_name, nullptr, event_tracer); + } + /** * Load the 'forward' method from the program and set up memory management if * needed. The loaded method is cached to reuse the next time it's executed. * + * @param[in] planned_memory The memory-planned buffers to use for mutable + * tensor data when executing the 'forward' method. * @param[in] event_tracer An event tracer used for tracking and logging * events. * * @returns An Error to indicate success or failure. */ ET_NODISCARD inline runtime::Error - load_forward(torch::executor::EventTracer *event_tracer = nullptr) { - return load_method("forward", event_tracer); + load_forward(runtime::HierarchicalAllocator *planned_memory = nullptr, + torch::executor::EventTracer *event_tracer = nullptr) { + return load_method("forward", planned_memory, event_tracer); + } + + ET_DEPRECATED ET_NODISCARD inline runtime::Error + load_forward(torch::executor::EventTracer *event_tracer) { + return load_forward(nullptr, event_tracer); } /** @@ -420,14 +463,16 @@ class Module { std::vector inputs; }; -private: std::string file_path_; + std::string data_map_path_; LoadMode load_mode_{LoadMode::MmapUseMlock}; std::shared_ptr program_; std::unique_ptr data_loader_; std::unique_ptr memory_allocator_; std::unique_ptr temp_allocator_; std::unique_ptr event_tracer_; + std::unique_ptr data_map_loader_; + std::unique_ptr data_map_; protected: std::unordered_map methods_; diff --git a/third-party/include/executorch/extension/tensor/tensor_ptr_maker.h b/third-party/include/executorch/extension/tensor/tensor_ptr_maker.h index f6a70dd4e8..c550b400f4 100644 --- a/third-party/include/executorch/extension/tensor/tensor_ptr_maker.h +++ b/third-party/include/executorch/extension/tensor/tensor_ptr_maker.h @@ -532,8 +532,7 @@ rand(std::vector sizes, } /** - * Creates a TensorPtr filled with random values between 0 and 1, with specified - * strides. + * Creates a TensorPtr filled with random values from a normal distribution. * * @param sizes A vector specifying the size of each dimension. * @param strides A vector specifying the stride for each dimension. @@ -572,8 +571,7 @@ inline TensorPtr randn_like( } /** - * Creates a TensorPtr filled with random values sampled from a normal - * distribution. + * Creates a TensorPtr filled with random values from a normal distribution. * * @param sizes A vector specifying the size of each dimension. * @param type The scalar type of the tensor elements. diff --git a/third-party/include/executorch/runtime/backend/backend_init_context.h b/third-party/include/executorch/runtime/backend/backend_init_context.h index 291cc720b1..b691cb0cc2 100644 --- a/third-party/include/executorch/runtime/backend/backend_init_context.h +++ b/third-party/include/executorch/runtime/backend/backend_init_context.h @@ -8,6 +8,7 @@ #pragma once #include +#include namespace executorch { namespace runtime { @@ -19,8 +20,11 @@ namespace runtime { class BackendInitContext final { public: explicit BackendInitContext(MemoryAllocator *runtime_allocator, - const char *method_name = nullptr) - : runtime_allocator_(runtime_allocator), method_name_(method_name) {} + EventTracer *event_tracer = nullptr, + const char *method_name = nullptr, + const NamedDataMap *named_data_map = nullptr) + : runtime_allocator_(runtime_allocator), method_name_(method_name), + named_data_map_(named_data_map) {} /** Get the runtime allocator passed from Method. It's the same runtime * executor used by the standard executor runtime and the life span is the @@ -28,6 +32,13 @@ class BackendInitContext final { */ MemoryAllocator *get_runtime_allocator() { return runtime_allocator_; } + /** + * Returns a pointer (null if not installed) to an instance of EventTracer to + * do profiling/debugging logging inside the delegate backend. Users will need + * access to this pointer to use any of the event tracer APIs. + */ + EventTracer *event_tracer() { return event_tracer_; } + /** Get the loaded method name from ExecuTorch runtime. Usually it's * "forward", however, if there are multiple methods in the .pte file, it can * be different. One example is that we may have prefill and decode methods in @@ -37,9 +48,16 @@ class BackendInitContext final { */ const char *get_method_name() const { return method_name_; } + /** Get the named data map from ExecuTorch runtime. + * This provides a way for backends to retrieve data blobs by key. + */ + const NamedDataMap *get_named_data_map() const { return named_data_map_; } + private: MemoryAllocator *runtime_allocator_ = nullptr; + EventTracer *event_tracer_ = nullptr; const char *method_name_ = nullptr; + const NamedDataMap *named_data_map_ = nullptr; }; } // namespace runtime diff --git a/third-party/include/executorch/runtime/backend/interface.h b/third-party/include/executorch/runtime/backend/interface.h index 42f8698e4c..1444f0af52 100644 --- a/third-party/include/executorch/runtime/backend/interface.h +++ b/third-party/include/executorch/runtime/backend/interface.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -137,6 +138,16 @@ struct Backend { */ ET_NODISCARD Error register_backend(const Backend &backend); +/** + * Returns the number of registered backends. + */ +size_t get_num_registered_backends(); + +/** + * Returns the backend name at the given index. + */ +Result get_backend_name(size_t index); + } // namespace runtime } // namespace executorch diff --git a/third-party/include/executorch/runtime/core/array_ref.h b/third-party/include/executorch/runtime/core/array_ref.h index e44682513d..01dd581663 100644 --- a/third-party/include/executorch/runtime/core/array_ref.h +++ b/third-party/include/executorch/runtime/core/array_ref.h @@ -19,7 +19,6 @@ // removed some implicit const -> non-const conversions that rely on // complicated std::enable_if meta-programming // removed a bunch of slice variants for simplicity... -// remove constructors for std::array // remove constructors and operators for std::vector // removed some prevention of accidental assignments from temporary that // required std::enable_if meta-programming @@ -27,8 +26,10 @@ #pragma once +#include #include +#include #include namespace executorch { @@ -86,6 +87,11 @@ template class ArrayRef final { /// Construct a ArrayRef from a range. ArrayRef(const T *begin, const T *end) : Data(begin), Length(end - begin) {} + /// Construct an ArrayRef from a std::array + template + /* implicit */ constexpr ArrayRef(const std::array &Arr) + : Data(Arr.data()), Length(N) {} + /// Construct a ArrayRef from a C array. template /* implicit */ constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {} @@ -129,7 +135,7 @@ template class ArrayRef final { if (Length != RHS.Length) { return false; } - for (size_t i = 0; i < this->Length; i++) { + for (const auto i : c10::irange(this->Length)) { if (Data[i] != RHS.Data[i]) { return false; } @@ -180,6 +186,12 @@ template ArrayRef makeArrayRef(const T *begin, const T *end) { return ArrayRef(begin, end); } +/// Construct an ArrayRef from a std::array. +template +ArrayRef makeArrayRef(const std::array &Arr) { + return Arr; +} + /// Construct an ArrayRef from an ArrayRef (no-op) (const) template ArrayRef makeArrayRef(const ArrayRef &Vec) { return Vec; diff --git a/third-party/include/executorch/runtime/core/data_loader.h b/third-party/include/executorch/runtime/core/data_loader.h index 25244fb924..01fc4caca2 100644 --- a/third-party/include/executorch/runtime/core/data_loader.h +++ b/third-party/include/executorch/runtime/core/data_loader.h @@ -48,6 +48,10 @@ class DataLoader { * Data used for initializing mutable tensors. */ Mutable, + /** + * Data used for initializing external tensors. + */ + External, }; /// Type of the segment. @@ -64,10 +68,10 @@ class DataLoader { SegmentInfo() = default; - explicit SegmentInfo(Type segment_type, size_t segment_index = 0, - const char *descriptor = nullptr) - : segment_type(segment_type), segment_index(segment_index), - descriptor(descriptor) {} + explicit SegmentInfo(Type segment_type_, size_t segment_index_ = 0, + const char *descriptor_ = nullptr) + : segment_type(segment_type_), segment_index(segment_index_), + descriptor(descriptor_) {} }; virtual ~DataLoader() = default; diff --git a/third-party/include/executorch/runtime/core/defines.h b/third-party/include/executorch/runtime/core/defines.h new file mode 100644 index 0000000000..ee47126826 --- /dev/null +++ b/third-party/include/executorch/runtime/core/defines.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @file + * Contains preprocessor definitions used by ExecuTorch core. + */ + +#pragma once + +// Enable ET_ENABLE_ENUM_STRINGS by default. This option gates inclusion of +// enum string names and can be disabled by explicitly setting it to 0. +#ifndef ET_ENABLE_ENUM_STRINGS +#define ET_ENABLE_ENUM_STRINGS 1 +#endif diff --git a/third-party/include/executorch/runtime/core/error.h b/third-party/include/executorch/runtime/core/error.h index 62ea8f16f1..9a07258eeb 100644 --- a/third-party/include/executorch/runtime/core/error.h +++ b/third-party/include/executorch/runtime/core/error.h @@ -79,6 +79,12 @@ enum class Error : error_code_t { /// Error caused by the contents of a program. InvalidProgram = 0x23, + /// Error caused by the contents of external data. + InvalidExternalData = 0x24, + + /// Does not have enough resources to perform the requested operation. + OutOfResources = 0x25, + /* * Delegate errors. */ @@ -123,6 +129,22 @@ using ::executorch::runtime::error_code_t; } \ } +/** + * A convenience macro to be used in utility functions that check whether input + * tensor(s) are valid, which are expected to return a boolean. Checks whether + * `cond` is true; if not, log the failed check with `message` and return false. + * + * @param[in] cond the condition to check + * @param[in] message an additional message to log with `cond` + */ +#define ET_CHECK_OR_RETURN_FALSE(cond__, message__, ...) \ + { \ + if (!(cond__)) { \ + ET_LOG(Error, "Check failed (%s): " message__, #cond__, ##__VA_ARGS__); \ + return false; \ + } \ + } + /** * If error__ is not Error::Ok, optionally log a message and return the error * from the current function, which must be of return type diff --git a/third-party/include/executorch/runtime/core/event_tracer.h b/third-party/include/executorch/runtime/core/event_tracer.h index ffb60066fe..b02a0e714d 100644 --- a/third-party/include/executorch/runtime/core/event_tracer.h +++ b/third-party/include/executorch/runtime/core/event_tracer.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,43 @@ enum class EventTracerDebugLogLevel { kIntermediateOutputs, }; +/** + * EventTracerFilterBase is an abstract base class that provides an interface + * for filtering events based on their name or delegate debug index. + * Derived classes should implement the filter method to define specific + * filtering logic. + */ +class EventTracerFilterBase { +public: + /** + * Filters events based on the given name or delegate debug index. + * + * Note that only one of either the name or delegate_debug_index should be + * passed in. + * + * @param[in] name A pointer to a string representing the `name` of the + * event. If `delegate_debug_index` is not set to kUnsetDebugHandle, `name` + * should be set to nullptr. + * + * @param[in] delegate_debug_index A DebugHandle representing the debug index + * of the delegate. If `name` is not nullptr, this should be set to + * kUnsetDebugHandle. + * + * @return A Result indicating whether the event matches the filter + * criteria. + * - True if the event matches the filter. + * - False if the event does not match or is unknown. + * - An error code if an error occurs during filtering. + */ + virtual Result filter(char *name, DebugHandle delegate_debug_index); + + /** + * Virtual destructor for the EventTracerFilterBase class. + * Ensures proper cleanup of derived class objects. + */ + virtual ~EventTracerFilterBase(); +}; + /** * Indicates the level of profiling that should be enabled. Profiling * events will be logged in increasing order of verbosity as we go down the @@ -279,8 +317,12 @@ class EventTracer { * based names are used by this delegate to identify ops executed in the * backend then kUnsetDebugHandle should be passed in here. * @param[in] output The tensor type output to be logged. + * @return A Result indicating the status of the logging operation. + * - True if the tensor type output was successfully logged. + * - False if the tensor type output was filtered out and not logged. + * - An error code if an error occurs during logging. */ - virtual void + virtual Result log_intermediate_output_delegate(const char *name, DebugHandle delegate_debug_index, const executorch::aten::Tensor &output) = 0; @@ -299,8 +341,13 @@ class EventTracer { * based names are used by this delegate to identify ops executed in the * backend then kUnsetDebugHandle should be passed in here. * @param[in] output The tensor array type output to be logged. + * @return A Result indicating the status of the logging operation. + * - True if the tensor array type output was successfully logged. + * - False if the tensor array type output was filtered out and not + * logged. + * - An error code if an error occurs during logging. */ - virtual void log_intermediate_output_delegate( + virtual Result log_intermediate_output_delegate( const char *name, DebugHandle delegate_debug_index, const ArrayRef output) = 0; @@ -318,8 +365,12 @@ class EventTracer { * based names are used by this delegate to identify ops executed in the * backend then kUnsetDebugHandle should be passed in here. * @param[in] output The int type output to be logged. + * @return A Result indicating the status of the logging operation. + * - True if the int type output was successfully logged. + * - False if the int type output was filtered out and not logged. + * - An error code if an error occurs during logging. */ - virtual void + virtual Result log_intermediate_output_delegate(const char *name, DebugHandle delegate_debug_index, const int &output) = 0; @@ -338,8 +389,12 @@ class EventTracer { * based names are used by this delegate to identify ops executed in the * backend then kUnsetDebugHandle should be passed in here. * @param[in] output The bool type output to be logged. + * @return A Result indicating the status of the logging operation. + * - True if the bool type output was successfully logged. + * - False if the bool type output was filtered out and not logged. + * - An error code if an error occurs during logging. */ - virtual void + virtual Result log_intermediate_output_delegate(const char *name, DebugHandle delegate_debug_index, const bool &output) = 0; @@ -358,8 +413,12 @@ class EventTracer { * based names are used by this delegate to identify ops executed in the * backend then kUnsetDebugHandle should be passed in here. * @param[in] output The double type output to be logged. + * @return A Result indicating the status of the logging operation. + * - True if the double type output was successfully logged. + * - False if the double type output was filtered out and not logged. + * - An error code if an error occurs during logging. */ - virtual void + virtual Result log_intermediate_output_delegate(const char *name, DebugHandle delegate_debug_index, const double &output) = 0; @@ -436,6 +495,12 @@ class EventTracer { event_tracer_profiling_level_ = profiling_level; } + /** + * Set the filter of event tracer for delegation intermediate outputs. + */ + void set_delegation_intermediate_output_filter( + EventTracerFilterBase *event_tracer_filter); + /** * Return the current level of event tracer profiling. */ diff --git a/third-party/include/executorch/runtime/core/exec_aten/exec_aten.h b/third-party/include/executorch/runtime/core/exec_aten/exec_aten.h index b63e9f3c0e..864cc8aba8 100644 --- a/third-party/include/executorch/runtime/core/exec_aten/exec_aten.h +++ b/third-party/include/executorch/runtime/core/exec_aten/exec_aten.h @@ -57,7 +57,7 @@ using TensorShapeDynamism = executorch::runtime::TensorShapeDynamism; using Tensor = at::Tensor; using TensorList = at::TensorList; using TensorImpl = at::TensorImpl; -using string_view = c10::string_view; +using string_view = std::string_view; template using ArrayRef = c10::ArrayRef; template using optional = std::optional; using nullopt_t = std::nullopt_t; @@ -100,7 +100,7 @@ template using ArrayRef = torch::executor::ArrayRef; template using optional = torch::executor::optional; using nullopt_t = torch::executor::nullopt_t; // NOLINTNEXTLINE(facebook-hte-NamespaceScopedStaticDeclaration) -static constexpr nullopt_t nullopt{0}; +using std::nullopt; using ScalarType = torch::executor::ScalarType; using TensorList = ArrayRef; using Scalar = torch::executor::Scalar; @@ -142,6 +142,6 @@ namespace exec_aten = executorch::aten; namespace torch { namespace executor { -using TensorList = exec_aten::TensorList; +using TensorList = ::executorch::aten::TensorList; } // namespace executor } // namespace torch diff --git a/third-party/include/executorch/runtime/core/exec_aten/util/dim_order_util.h b/third-party/include/executorch/runtime/core/exec_aten/util/dim_order_util.h index c1ea45b88c..8ed3431748 100644 --- a/third-party/include/executorch/runtime/core/exec_aten/util/dim_order_util.h +++ b/third-party/include/executorch/runtime/core/exec_aten/util/dim_order_util.h @@ -8,7 +8,10 @@ #pragma once +#include #include +#include +#include #include #include @@ -20,8 +23,8 @@ namespace runtime { namespace { template bool validate_dim_order(const DimOrderType *dim_order, const size_t dims) { - for (int32_t i = 0; i < dims; ++i) { - if (dim_order[i] >= dims) { + for (size_t i = 0; i < dims; ++i) { + if (dim_order[i] >= static_cast(dims)) { return false; } } @@ -39,8 +42,8 @@ bool validate_dim_order(const DimOrderType *dim_order, const size_t dims) { template inline bool is_contiguous_dim_order(const DimOrderType *dim_order, const size_t dims) { - for (int i = 0; i < dims; ++i) { - if (dim_order[i] != i) { + for (size_t i = 0; i < dims; ++i) { + if (dim_order[i] != static_cast(i)) { return false; } } @@ -61,7 +64,7 @@ bool is_channels_last_dim_order(const DimOrderType *dim_order, return false; } // 4-dim tensor is interpreted as NCHW, 5-dim tensor is interpreted as NCHWD - size_t channels_dim = 1; + DimOrderType channels_dim = 1; // Last value in the dim order should be the channels dim if (dim_order[dims - 1] != channels_dim) { return false; @@ -70,8 +73,8 @@ bool is_channels_last_dim_order(const DimOrderType *dim_order, if (dim_order[0] != 0) { return false; } - int d = 1; - while (d < dims - 1) { + DimOrderType d = 1; + while (d < static_cast(dims) - 1) { if (dim_order[d] != d + 1) { return false; } @@ -153,8 +156,8 @@ template struct StrideDimOrder { StridesType stride; DimOrderType dim_order; - StrideDimOrder(StridesType stride, DimOrderType dim_order) - : stride(stride), dim_order(dim_order) {} + StrideDimOrder(StridesType stride_, DimOrderType dim_order_) + : stride(stride_), dim_order(dim_order_) {} StrideDimOrder() = default; bool operator>(const StrideDimOrder &other) const { // descending order @@ -238,11 +241,12 @@ ET_NODISCARD inline Error stride_to_dim_order(const StridesType *strides, sorter.quick_sort(array, 0, dims - 1); - for (auto i = 0; i < dims; i++) { + for (const auto i : c10::irange(dims)) { dim_order[i] = array[i].dim_order; } return Error::Ok; } + } // namespace runtime } // namespace executorch diff --git a/third-party/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h b/third-party/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h index da20c8c90e..82ad7dbe5b 100644 --- a/third-party/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h +++ b/third-party/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h @@ -52,8 +52,8 @@ using string_view = torch::executor::string_view; } // namespace aten } // namespace executorch #endif // USE_ATEN_LIB -// DEPRECATED: The exec_aten:: namespace is deprecated. Use executorch::aten:: -// instead. +// DEPRECATED: The executorch::aten:: namespace is deprecated. Use +// executorch::aten:: instead. namespace exec_aten = ::executorch::aten; namespace executorch { @@ -250,6 +250,10 @@ ET_FORALL_SCALAR_TYPES(SPECIALIZE_CppTypeToScalarType) _(ANOTHER_INPUT1, ANOTHER_INPUT2, ::executorch::aten::Half, Half) \ _(ANOTHER_INPUT1, ANOTHER_INPUT2, ::executorch::aten::BFloat16, BFloat16) +#define ET_FORALL_REALHBBF16_TYPES_WITH2(ANOTHER_INPUT1, ANOTHER_INPUT2, _) \ + ET_FORALL_REALHBF16_TYPES_WITH2(ANOTHER_INPUT2, ANOTHER_INPUT2, _) \ + _(ANOTHER_INPUT1, ANOTHER_INPUT2, bool, Bool) + // For macros that take `SCALARTYPEn` parameters, those parameters should be // an unquoted/unqualified enumerator name like `Int` or `Float`. #define ET_FORALL_REAL_TYPES_AND(SCALARTYPE, _) \ @@ -343,8 +347,13 @@ ET_FORALL_SCALAR_TYPES(SPECIALIZE_CppTypeToScalarType) // In this context, "COMPLEX" means complex types based on primitive C types, // which is why ComplexHalf is not included. #define ET_FORALL_COMPLEX_TYPES(_) \ - _(::torch::executor::complex, ComplexFloat) \ - _(::torch::executor::complex, ComplexDouble) + _(::executorch::aten::complex, ComplexFloat) \ + _(::executorch::aten::complex, ComplexDouble) + +#define ET_FORALL_COMPLEXH_TYPES(_) \ + _(::executorch::aten::complex<::executorch::aten::Half>, ComplexHalf) \ + _(::executorch::aten::complex, ComplexFloat) \ + _(::executorch::aten::complex, ComplexDouble) // // Utility functions to retrieve metadata for a given ScalarType @@ -577,7 +586,7 @@ inline bool isUnderlying(::executorch::aten::ScalarType type, return type == ::executorch::runtime::toUnderlying(qtype); } -inline ::executorch::aten::ScalarType +inline constexpr ::executorch::aten::ScalarType toRealValueType(::executorch::aten::ScalarType t) { switch (t) { case ::executorch::aten::ScalarType::ComplexHalf: @@ -591,7 +600,7 @@ toRealValueType(::executorch::aten::ScalarType t) { } } -inline ::executorch::aten::ScalarType +inline constexpr ::executorch::aten::ScalarType toComplexType(::executorch::aten::ScalarType t) { switch (t) { case ::executorch::aten::ScalarType::BFloat16: @@ -958,8 +967,11 @@ struct promote_types { #define ET_INTERNAL_SWITCH_CASE_REAL_TYPES_AND3(ADDITIONAL1, ADDITIONAL2, \ ADDITIONAL3, CTYPE_ALIAS, ...) \ - ET_INTERNAL_SWITCH_CASE_REAL_TYPES_AND2(ADDITIONAL1, ADDITIONAL2, \ - CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE_REAL_TYPES(CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ADDITIONAL1, \ + CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ADDITIONAL2, \ + CTYPE_ALIAS, __VA_ARGS__) \ ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ADDITIONAL3, \ CTYPE_ALIAS, __VA_ARGS__) @@ -998,6 +1010,13 @@ struct promote_types { ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ADDITIONAL2, \ CTYPE_ALIAS, __VA_ARGS__) +#define ET_INTERNAL_SWITCH_CASE_FLOAT_TYPES_AND3( \ + ADDITIONAL1, ADDITIONAL2, ADDITIONAL3, CTYPE_ALIAS, ...) \ + ET_INTERNAL_SWITCH_CASE_FLOAT_TYPES_AND2(ADDITIONAL1, ADDITIONAL2, \ + CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ADDITIONAL3, \ + CTYPE_ALIAS, __VA_ARGS__) + #define ET_INTERNAL_SWITCH_CASE_QINT_TYPES(CTYPE_ALIAS, ...) \ ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::QInt8, CTYPE_ALIAS, \ __VA_ARGS__) \ @@ -1016,6 +1035,14 @@ struct promote_types { ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ComplexDouble, \ CTYPE_ALIAS, __VA_ARGS__) +#define ET_INTERNAL_SWITCH_CASE_COMPLEXH_TYPES(CTYPE_ALIAS, ...) \ + ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ComplexHalf, \ + CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ComplexFloat, \ + CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::ComplexDouble, \ + CTYPE_ALIAS, __VA_ARGS__) + #define ET_INTERNAL_SWITCH_CASE_SCALAR_OBJ_TYPES(CTYPE_ALIAS, ...) \ ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::Bool, CTYPE_ALIAS, \ __VA_ARGS__) \ @@ -1125,6 +1152,20 @@ struct promote_types { ET_SWITCH_REAL_TYPES_AND3(Half, Bool, BFloat16, TYPE, CONTEXT, NAME, \ CTYPE_ALIAS, __VA_ARGS__) +#define ET_SWITCH_REALHBBF16_AND_UINT_TYPES(TYPE, CONTEXT, NAME, CTYPE_ALIAS, \ + ...) \ + ET_INTERNAL_SWITCH( \ + TYPE, CONTEXT, NAME, \ + ET_INTERNAL_SWITCH_CASE_REAL_TYPES_AND3(Half, Bool, BFloat16, \ + CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::UInt16, \ + CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE(::executorch::aten::ScalarType::UInt32, \ + CTYPE_ALIAS, __VA_ARGS__) \ + ET_INTERNAL_SWITCH_CASE( \ + ::executorch::aten::ScalarType::UInt64, CTYPE_ALIAS, \ + __VA_ARGS__)) + #define ET_SWITCH_INT_TYPES(TYPE, CONTEXT, NAME, CTYPE_ALIAS, ...) \ ET_INTERNAL_SWITCH( \ TYPE, CONTEXT, NAME, \ @@ -1153,6 +1194,13 @@ struct promote_types { ET_INTERNAL_SWITCH_CASE_FLOAT_TYPES_AND2( \ ADDITIONAL1, ADDITIONAL2, CTYPE_ALIAS, __VA_ARGS__)) +#define ET_SWITCH_FLOAT_TYPES_AND3(ADDITIONAL1, ADDITIONAL2, ADDITIONAL3, \ + TYPE, CONTEXT, NAME, CTYPE_ALIAS, ...) \ + ET_INTERNAL_SWITCH( \ + TYPE, CONTEXT, NAME, \ + ET_INTERNAL_SWITCH_CASE_FLOAT_TYPES_AND3( \ + ADDITIONAL1, ADDITIONAL2, ADDITIONAL3, CTYPE_ALIAS, __VA_ARGS__)) + #define ET_SWITCH_FLOATH_TYPES(TYPE, CONTEXT, NAME, CTYPE_ALIAS, ...) \ ET_SWITCH_FLOAT_TYPES_AND(Half, TYPE, CONTEXT, NAME, CTYPE_ALIAS, __VA_ARGS__) @@ -1160,6 +1208,11 @@ struct promote_types { ET_SWITCH_FLOAT_TYPES_AND2(Half, BFloat16, TYPE, CONTEXT, NAME, CTYPE_ALIAS, \ __VA_ARGS__) +#define ET_SWITCH_FLOATHBF16_TYPES_AND(ADDITIONAL, TYPE, CONTEXT, NAME, \ + CTYPE_ALIAS, ...) \ + ET_SWITCH_FLOAT_TYPES_AND3(Half, BFloat16, ADDITIONAL, TYPE, CONTEXT, NAME, \ + CTYPE_ALIAS, __VA_ARGS__) + #define ET_SWITCH_QINT_TYPES(TYPE, CONTEXT, NAME, CTYPE_ALIAS, ...) \ ET_INTERNAL_SWITCH( \ TYPE, CONTEXT, NAME, \ @@ -1170,6 +1223,11 @@ struct promote_types { TYPE, CONTEXT, NAME, \ ET_INTERNAL_SWITCH_CASE_COMPLEX_TYPES(CTYPE_ALIAS, __VA_ARGS__)) +#define ET_SWITCH_COMPLEXH_TYPES(TYPE, CONTEXT, NAME, CTYPE_ALIAS, ...) \ + ET_INTERNAL_SWITCH( \ + TYPE, CONTEXT, NAME, \ + ET_INTERNAL_SWITCH_CASE_COMPLEXH_TYPES(CTYPE_ALIAS, __VA_ARGS__)) + #define ET_SWITCH_SCALAR_OBJ_TYPES(TYPE, CONTEXT, NAME, CTYPE_ALIAS, ...) \ ET_INTERNAL_SWITCH( \ TYPE, CONTEXT, NAME, \ diff --git a/third-party/include/executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h b/third-party/include/executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h new file mode 100644 index 0000000000..6e072ab058 --- /dev/null +++ b/third-party/include/executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +namespace executorch::runtime { +/** + * The expected output size may not be the existing size of any inputs and + * outputs if the operator supports both broadcast and dynamic shape. + * Therefore such operators needs extra space to store the calculated expected + * output size. such dynamic allocation is troublesome in executorch so we can + * just hard code a static value of a relatively small value because users + * don't create high dimensional tensors. + */ +constexpr size_t kTensorDimensionLimit = 16; +} // namespace executorch::runtime diff --git a/third-party/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.h b/third-party/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.h new file mode 100644 index 0000000000..4db9b48fab --- /dev/null +++ b/third-party/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace executorch::runtime { + +/** + * Maximum size of a string returned by tensor_shape_to_c_string, for + * stack allocation. + */ +constexpr size_t kTensorShapeStringSizeLimit = + 1 + /* opening parenthesis */ + 10 * kTensorDimensionLimit + /* maximum digits we will print; update + * kMaximumPrintableTensorShapeElement + * if changing */ + 2 * kTensorDimensionLimit + /* comma and space after each item, + * overwritten with closing paren and + * NUL terminator for last element */ + 1; /* padding for temporary NUL terminator for simplicity of implementation + */ + +namespace internal { +constexpr size_t kMaximumPrintableTensorShapeElement = + std::numeric_limits::max(); +} // namespace internal + +/** + * Convert a shape to a NUL-terminated C string with limited size. If + * elements of the shape are larger than + * kMaximumPrintableTensorShapeElement, those elements will be + * rendered as ERR instead. + * + * NOTE: There are two overloads of this function to support both ATen + * tensors and ExecuTorch Tensors, which have different SizesType, + * while also avoiding a dependency on exec_aten.h from this header + * because that would cause a circular dependency. + */ +std::array +tensor_shape_to_c_string(executorch::runtime::Span shape); + +/** + * Convert a shape to a NUL-terminated C string with limited size. If + * elements of the shape are larger than + * kMaximumPrintableTensorShapeElement, those elements will be + * rendered as ERR instead. + * + * NOTE: There are two overloads of this function to support both ATen + * tensors and ExecuTorch Tensors, which have different SizesType, + * while also avoiding a dependency on exec_aten.h from this header + * because that would cause a circular dependency. + */ +std::array +tensor_shape_to_c_string(executorch::runtime::Span shape); + +} // namespace executorch::runtime diff --git a/third-party/include/executorch/runtime/core/exec_aten/util/tensor_util.h b/third-party/include/executorch/runtime/core/exec_aten/util/tensor_util.h index 935f9f5c31..322ab061dc 100644 --- a/third-party/include/executorch/runtime/core/exec_aten/util/tensor_util.h +++ b/third-party/include/executorch/runtime/core/exec_aten/util/tensor_util.h @@ -9,10 +9,12 @@ #pragma once #include -#include // std::array +#include // std::array +#include #include // PRId64 #include #include // size_t + #include #include @@ -20,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -269,35 +273,22 @@ }) /** + * DEPRECATED: Please use ET_CHECK_OR_RETURN_FALSE instead and provide + * an informative message. (For example, the values of any variables used in + * `cond` would not be reported automatically by this macro.) + * * A convenience macro to be used in utility functions that check whether input * tensor(s) are valid, which are expected to return a boolean. Checks whether * `cond` is true; if not, log the failed check and return false. * * @param[in] cond the condition to check */ -#define ET_LOG_AND_RETURN_IF_FALSE(cond) \ - do { \ - if (!(cond)) { \ - ET_LOG(Error, "Check failed (%s): ", #cond); \ - return false; \ - } \ - } while (false) +#define ET_LOG_AND_RETURN_IF_FALSE(cond) ET_CHECK_OR_RETURN_FALSE(cond, "") /** - * A convenience macro to be used in utility functions that check whether input - * tensor(s) are valid, which are expected to return a boolean. Checks whether - * `cond` is true; if not, log the failed check with `message` and return false. - * - * @param[in] cond the condition to check - * @param[in] message an additional message to log with `cond` + * DEPRECATED: Please use ET_CHECK_OR_RETURN_FALSE instead. */ -#define ET_LOG_MSG_AND_RETURN_IF_FALSE(cond, message, ...) \ - do { \ - if (!(cond)) { \ - ET_LOG(Error, "Check failed (%s): " message, #cond, ##__VA_ARGS__); \ - return false; \ - } \ - } while (false) +#define ET_LOG_MSG_AND_RETURN_IF_FALSE ET_CHECK_OR_RETURN_FALSE /** * If `cond` is false, log `cond` and return from the kernel with a failure @@ -355,7 +346,7 @@ namespace runtime { * upper_bound - 1, inclusive. */ inline bool dim_is_valid(int64_t dim, int64_t upper_bound) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( dim >= -upper_bound && dim < upper_bound, "Dimension %" PRId64 " is out of range. Dimension should be between %" PRId64 " and %" PRId64 @@ -388,30 +379,55 @@ inline ssize_t nonempty_size(const executorch::aten::Tensor &tensor, inline bool tensor_can_cast_to(executorch::aten::Tensor a, executorch::aten::ScalarType dtype) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( - torch::executor::canCast(a.scalar_type(), dtype), - "Tensor of dtype %s cannot cast to dtype %s", - torch::executor::toString(a.scalar_type()), - torch::executor::toString(dtype)); + ET_CHECK_OR_RETURN_FALSE(torch::executor::canCast(a.scalar_type(), dtype), + "Tensor of dtype %s cannot cast to dtype %s", + torch::executor::toString(a.scalar_type()), + torch::executor::toString(dtype)); return true; } inline bool tensor_is_bool_type(executorch::aten::Tensor t) { + ET_CHECK_OR_RETURN_FALSE(t.scalar_type() == + executorch::aten::ScalarType::Bool, + "Expected to find bool type, but tensor has type %s", + torch::executor::toString(t.scalar_type())); + + return true; +} + +inline bool tensor_is_type(executorch::aten::Tensor t, + executorch::aten::ScalarType dtype) { + ET_CHECK_OR_RETURN_FALSE(t.scalar_type() == dtype, + "Expected to find %s type, but tensor has type %s", + torch::executor::toString(dtype), + torch::executor::toString(t.scalar_type())); + + return true; +} + +inline bool tensor_is_type(executorch::aten::Tensor t, + executorch::aten::ScalarType dtype, + executorch::aten::ScalarType dtype2) { ET_LOG_MSG_AND_RETURN_IF_FALSE( - t.scalar_type() == executorch::aten::ScalarType::Bool, - "Expected to find bool type, but tensor has type %s", + t.scalar_type() == dtype || t.scalar_type() == dtype2, + "Expected to find %s or %s type, but tensor has type %s", + torch::executor::toString(dtype), torch::executor::toString(dtype2), torch::executor::toString(t.scalar_type())); return true; } inline bool tensor_is_type(executorch::aten::Tensor t, - executorch::aten::ScalarType dtype) { + executorch::aten::ScalarType dtype, + executorch::aten::ScalarType dtype2, + executorch::aten::ScalarType dtype3) { ET_LOG_MSG_AND_RETURN_IF_FALSE( - t.scalar_type() == dtype, - "Expected to find %s type, but tensor has type %s", - torch::executor::toString(dtype), + t.scalar_type() == dtype || t.scalar_type() == dtype2 || + t.scalar_type() == dtype3, + "Expected to find %s, %s, or %s type, but tensor has type %s", + torch::executor::toString(dtype), torch::executor::toString(dtype2), + torch::executor::toString(dtype3), torch::executor::toString(t.scalar_type())); return true; @@ -419,7 +435,7 @@ inline bool tensor_is_type(executorch::aten::Tensor t, inline bool tensor_is_integral_type(executorch::aten::Tensor t, bool includeBool = false) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( torch::executor::isIntegralType(t.scalar_type(), includeBool), "Expected to find a integral type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -428,7 +444,7 @@ inline bool tensor_is_integral_type(executorch::aten::Tensor t, } inline bool tensor_is_floating_type(executorch::aten::Tensor t) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( torch::executor::isFloatingType(t.scalar_type()), "Expected to find a floating type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -437,7 +453,7 @@ inline bool tensor_is_floating_type(executorch::aten::Tensor t) { } inline bool tensor_is_real_type(executorch::aten::Tensor t) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( torch::executor::isRealType(t.scalar_type()), "Expected to find a real type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -446,7 +462,7 @@ inline bool tensor_is_real_type(executorch::aten::Tensor t) { } inline bool tensor_is_realh_type(executorch::aten::Tensor t) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( torch::executor::isRealHType(t.scalar_type()), "Expected to find a real type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -455,7 +471,7 @@ inline bool tensor_is_realh_type(executorch::aten::Tensor t) { } inline bool tensor_is_realhbf16_type(executorch::aten::Tensor t) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( executorch::runtime::isRealHBF16Type(t.scalar_type()), "Expected to find a real type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -464,7 +480,7 @@ inline bool tensor_is_realhbf16_type(executorch::aten::Tensor t) { } inline bool tensor_is_realhb_type(executorch::aten::Tensor t) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( torch::executor::isRealHBType(t.scalar_type()), "Expected to find a real type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -473,7 +489,7 @@ inline bool tensor_is_realhb_type(executorch::aten::Tensor t) { } inline bool tensor_is_realhbbf16_type(executorch::aten::Tensor t) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( executorch::runtime::isRealHBBF16Type(t.scalar_type()), "Expected to find a real type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -482,7 +498,7 @@ inline bool tensor_is_realhbbf16_type(executorch::aten::Tensor t) { } inline bool tensor_is_complex_type(executorch::aten::Tensor t) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( torch::executor::isComplexType(t.scalar_type()), "Expected to find a complex type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -491,7 +507,7 @@ inline bool tensor_is_complex_type(executorch::aten::Tensor t) { } inline bool tensor_is_bits_type(executorch::aten::Tensor t) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( torch::executor::isBitsType(t.scalar_type()), "Expected to find a bits type, but tensor has type %s", torch::executor::toString(t.scalar_type())); @@ -501,61 +517,64 @@ inline bool tensor_is_bits_type(executorch::aten::Tensor t) { inline bool tensors_have_same_dtype(executorch::aten::Tensor a, executorch::aten::Tensor b) { - ET_LOG_MSG_AND_RETURN_IF_FALSE(a.scalar_type() == b.scalar_type(), - ET_TENSOR_CHECK_PREFIX__ ": dtype={%s, %s}", - torch::executor::toString(a.scalar_type()), - torch::executor::toString(b.scalar_type())); + ET_CHECK_OR_RETURN_FALSE(a.scalar_type() == b.scalar_type(), + ET_TENSOR_CHECK_PREFIX__ ": dtype={%s, %s}", + torch::executor::toString(a.scalar_type()), + torch::executor::toString(b.scalar_type())); return true; } inline bool tensors_have_same_dtype(executorch::aten::Tensor a, executorch::aten::Tensor b, executorch::aten::Tensor c) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( - a.scalar_type() == b.scalar_type() && b.scalar_type() == c.scalar_type(), - ET_TENSOR_CHECK_PREFIX__ ": dtype={%s, %s, %s}", - torch::executor::toString(a.scalar_type()), - torch::executor::toString(b.scalar_type()), - torch::executor::toString(c.scalar_type())); + ET_CHECK_OR_RETURN_FALSE(a.scalar_type() == b.scalar_type() && + b.scalar_type() == c.scalar_type(), + ET_TENSOR_CHECK_PREFIX__ ": dtype={%s, %s, %s}", + torch::executor::toString(a.scalar_type()), + torch::executor::toString(b.scalar_type()), + torch::executor::toString(c.scalar_type())); return true; } inline bool tensor_is_rank(executorch::aten::Tensor t, size_t rank) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( - t.dim() == rank, "Expected tensor.dim() to be %zu, but got %zu", - static_cast(rank), static_cast(t.dim())); + ET_CHECK_OR_RETURN_FALSE(static_cast(t.dim()) == rank, + "Expected tensor.dim() to be %zu, but got %zu", + static_cast(rank), + static_cast(t.dim())); return true; } inline bool tensor_has_rank_greater_or_equal_to(executorch::aten::Tensor t, size_t rank) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( - t.dim() >= rank, "Expected tensor.dim() to be >= %zu, but got %zu", - static_cast(rank), static_cast(t.dim())); + ET_CHECK_OR_RETURN_FALSE(static_cast(t.dim()) >= rank, + "Expected tensor.dim() to be >= %zu, but got %zu", + static_cast(rank), + static_cast(t.dim())); return true; } inline bool tensor_has_rank_smaller_or_equal_to(executorch::aten::Tensor t, size_t rank) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( - t.dim() <= rank, "Expected tensor.dim() to be <= %zu, but got %zu", - static_cast(rank), static_cast(t.dim())); + ET_CHECK_OR_RETURN_FALSE(static_cast(t.dim()) <= rank, + "Expected tensor.dim() to be <= %zu, but got %zu", + static_cast(rank), + static_cast(t.dim())); return true; } inline bool tensor_has_dim(executorch::aten::Tensor t, int64_t d) { if (t.dim() == 0) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( d == 0 || d == -1, "dim must be 0 or -1 for 0-dim tensor, got %" PRId64, d); } else { - ET_LOG_MSG_AND_RETURN_IF_FALSE( - d > 0 ? d < t.dim() : t.dim() + d >= 0, - "%zu-dim tensor does not have dim at index %zu", - static_cast(t.dim()), static_cast(d)); + ET_CHECK_OR_RETURN_FALSE(d > 0 ? d < t.dim() : t.dim() + d >= 0, + "%zu-dim tensor does not have dim at index %zu", + static_cast(t.dim()), + static_cast(d)); } return true; } @@ -577,7 +596,7 @@ inline bool tensor_dim_has_index(executorch::aten::Tensor t, int64_t d, // Dimension must have been already checked by tensor_has_dim ET_CHECK(d >= 0 && d < t.dim()); - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( ix >= -t.size(d) && ix < t.size(d), "index %" PRId64 " out of range [-%zu,%zu) at dimension %" PRId64 ")", ix, static_cast(t.size(d)), static_cast(t.size(d)), d); @@ -588,13 +607,15 @@ inline bool tensors_have_same_size_at_dims(executorch::aten::Tensor a, size_t dim_a, executorch::aten::Tensor b, size_t dim_b) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( - dim_a < a.dim(), "Cannot retrieve dim %zu from tensor with dim %zu", - static_cast(dim_a), static_cast(a.dim())); - ET_LOG_MSG_AND_RETURN_IF_FALSE( - dim_b < b.dim(), "Cannot retrieve dim %zu from tensor with dim %zu", - static_cast(dim_b), static_cast(b.dim())); - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE(dim_a < static_cast(a.dim()), + "Cannot retrieve dim %zu from tensor with dim %zu", + static_cast(dim_a), + static_cast(a.dim())); + ET_CHECK_OR_RETURN_FALSE(dim_b < static_cast(b.dim()), + "Cannot retrieve dim %zu from tensor with dim %zu", + static_cast(dim_b), + static_cast(b.dim())); + ET_CHECK_OR_RETURN_FALSE( a.size(dim_a) == b.size(dim_b), ET_TENSOR_CHECK_PREFIX__ ": a.size(%zu) = %zu does not match b.size(%zu) = %zu", @@ -616,7 +637,9 @@ inline bool tensors_have_same_shape(executorch::aten::Tensor a, ET_TENSOR_CHECK_PREFIX__ ": numel=(%zu, %zu), dim=(%zu, %zu)", static_cast(a.numel()), static_cast(b.numel()), static_cast(a.dim()), static_cast(b.dim())); - for (size_t d = 0; d < ET_MIN2(a.dim(), b.dim()); ++d) { + // Using [[maybe_unused]] as ET_LOG may not trigger based on verbosity + for ([[maybe_unused]] const auto d : + c10::irange(ET_MIN2(a.dim(), b.dim()))) { ET_LOG(Error, " size(%zu): (%zu, %zu)", static_cast(d), static_cast(a.size(d)), static_cast(b.size(d))); } @@ -645,7 +668,8 @@ inline bool tensors_have_same_shape(executorch::aten::Tensor a, static_cast(a.numel()), static_cast(b.numel()), static_cast(c.numel()), static_cast(a.dim()), static_cast(b.dim()), static_cast(c.dim())); - for (size_t d = 0; d < ET_MIN3(a.dim(), b.dim(), c.dim()); ++d) { + for ([[maybe_unused]] const auto d : + c10::irange(ET_MIN3(a.dim(), b.dim(), c.dim()))) { ET_LOG(Error, " size(%zu): (%zu, %zu, %zu)", static_cast(d), static_cast(a.size(d)), static_cast(b.size(d)), static_cast(c.size(d))); @@ -677,7 +701,8 @@ inline bool tensor_has_expected_size( static_cast(expected_sizes.size())); size_t a_dim = static_cast(a.dim()); size_t expected_dim = static_cast(expected_sizes.size()); - for (size_t d = 0; d < ET_MIN2(a_dim, expected_dim); ++d) { + for ([[maybe_unused]] const auto d : + c10::irange(ET_MIN2(a_dim, expected_dim))) { ET_LOG(Error, " size(%zu): (%zu, %zu)", static_cast(d), static_cast(a.size(d)), static_cast(expected_sizes[d])); @@ -693,7 +718,8 @@ inline bool tensors_have_same_strides(executorch::aten::Tensor a, if (a.strides() != b.strides()) { ET_LOG(Error, ET_TENSOR_CHECK_PREFIX__ ": dim=(%zu, %zu)", static_cast(a.dim()), static_cast(b.dim())); - for (size_t d = 0; d < ET_MIN2(a.dim(), b.dim()); ++d) { + for ([[maybe_unused]] const auto d : + c10::irange(ET_MIN2(a.dim(), b.dim()))) { ET_LOG(Error, " stride(%zu): (%zu, %zu)", static_cast(d), static_cast(a.strides()[d]), static_cast(b.strides()[d])); @@ -711,7 +737,8 @@ inline bool tensors_have_same_strides(executorch::aten::Tensor a, ET_LOG(Error, ET_TENSOR_CHECK_PREFIX__ ": dim=(%zu, %zu, %zu)", static_cast(a.dim()), static_cast(b.dim()), static_cast(c.dim())); - for (size_t d = 0; d < ET_MIN3(a.dim(), b.dim(), c.dim()); ++d) { + for ([[maybe_unused]] const auto d : + c10::irange(ET_MIN3(a.dim(), b.dim(), c.dim()))) { ET_LOG(Error, " stride(%zu): (%zu, %zu, %zu)", static_cast(d), static_cast(a.strides()[d]), static_cast(b.strides()[d]), @@ -730,13 +757,13 @@ inline bool tensor_is_contiguous(executorch::aten::Tensor t) { if (strides.size() == 0) { return true; } - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( strides[strides.size() - 1] == 1, "Tensor is not contiguous; the stride of the last dimension must be 1, " "but got %zu", static_cast(strides[strides.size() - 1])); for (int i = strides.size() - 1; i > 0; --i) { - ET_LOG_MSG_AND_RETURN_IF_FALSE( + ET_CHECK_OR_RETURN_FALSE( strides[i - 1] == strides[i] * sizes[i], "Tensor is not contiguous; the stride of dim %zu should be equal to " "strides[%zu] * sizes[%zu] = %zu, but found %zu", @@ -749,9 +776,9 @@ inline bool tensor_is_contiguous(executorch::aten::Tensor t) { inline bool tensors_have_same_rank(executorch::aten::Tensor a, executorch::aten::Tensor b) { - ET_LOG_MSG_AND_RETURN_IF_FALSE(a.dim() == b.dim(), - ET_TENSOR_CHECK_PREFIX__ ": rank={%zd, %zd}", - ssize_t(a.dim()), ssize_t(b.dim())); + ET_CHECK_OR_RETURN_FALSE(a.dim() == b.dim(), + ET_TENSOR_CHECK_PREFIX__ ": rank={%zd, %zd}", + ssize_t(a.dim()), ssize_t(b.dim())); return true; } @@ -759,16 +786,6 @@ inline bool tensor_is_scalar(executorch::aten::Tensor t) { return t.dim() == 0 && t.numel() == 1; } -/** - * The expected output size may not be the existing size of any inputs and - * outputs if the operator supports both broadcast and dynamic shape. - * Therefore such operators needs extra space to store the calculated expected - * output size. such dynamic allocation is troublesome in executorch so we can - * just hard code a static value of a relatively small value because users - * don't create high dimensional tensors. - */ -constexpr size_t kTensorDimensionLimit = 16; - /// Returns the product of dim[0:dim), not including dim. inline size_t getLeadingDims(const executorch::aten::Tensor &tensor, int64_t dim) { @@ -777,7 +794,7 @@ inline size_t getLeadingDims(const executorch::aten::Tensor &tensor, " should be in the range [0, tensor.dim() %zd].", dim, ssize_t(tensor.dim())); size_t dims = 1; - for (size_t i = 0; i < dim; ++i) { + for (const auto i : c10::irange(dim)) { dims *= static_cast(tensor.size(i)); } return dims; @@ -791,7 +808,7 @@ inline size_t getTrailingDims(const executorch::aten::Tensor &tensor, " should be in the range [-1, tensor.dim() -1 %zd).", dim, ssize_t(tensor.dim())); size_t dims = 1; - for (size_t i = dim + 1; i < tensor.dim(); ++i) { + for (size_t i = dim + 1; i < static_cast(tensor.dim()); ++i) { dims *= static_cast(tensor.size(i)); } return dims; @@ -860,7 +877,7 @@ inline size_t coordinateToIndexWithTrailingDimsMemo( */ inline void indexToCoordinate(const executorch::aten::Tensor &tensor, size_t index, size_t *coordinate) { - ET_CHECK(index < tensor.numel()); + ET_CHECK(index < static_cast(tensor.numel())); for (auto i = 0; i < tensor.dim(); ++i) { auto dim = tensor.dim() - 1 - i; size_t dim_size = tensor.size(dim); @@ -917,8 +934,11 @@ bool extract_scalar_tensor(executorch::aten::Tensor tensor, INT_T *out_val) { * be represented by FLOAT_T. */ template ::value, - bool>::type = true> + typename std::enable_if< + std::is_floating_point_v || + std::is_same_v || + std::is_same_v, + bool>::type = true> bool extract_scalar_tensor(executorch::aten::Tensor tensor, FLOAT_T *out_val) { if (tensor.numel() != 1) { return false; @@ -937,7 +957,7 @@ bool extract_scalar_tensor(executorch::aten::Tensor tensor, FLOAT_T *out_val) { } switch (tensor.scalar_type()) { - ET_FORALL_REAL_TYPES(CASE_REAL_DTYPE); + ET_FORALL_REALHBF16_TYPES(CASE_REAL_DTYPE); default: return false; } diff --git a/third-party/include/executorch/runtime/core/hierarchical_allocator.h b/third-party/include/executorch/runtime/core/hierarchical_allocator.h index d894c08033..279934d484 100644 --- a/third-party/include/executorch/runtime/core/hierarchical_allocator.h +++ b/third-party/include/executorch/runtime/core/hierarchical_allocator.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -58,12 +59,13 @@ class HierarchicalAllocator final { size_t offset_bytes, size_t size_bytes) { ET_CHECK_OR_RETURN_ERROR(memory_id < buffers_.size(), InvalidArgument, - "id %" PRIu32 " >= %zu", memory_id, + "id %" PRIu32 " >= %" ET_PRIsize_t, memory_id, buffers_.size()); Span buffer = buffers_[memory_id]; ET_CHECK_OR_RETURN_ERROR( offset_bytes + size_bytes <= buffer.size(), MemoryAllocationFailed, - "offset_bytes (%zu) + size_bytes (%zu) >= allocator size (%zu) " + "offset_bytes (%" ET_PRIsize_t ") + size_bytes (%" ET_PRIsize_t + ") >= allocator size (%" ET_PRIsize_t ") " "for memory_id %" PRIu32, offset_bytes, size_bytes, buffer.size(), memory_id); return buffer.data() + offset_bytes; @@ -82,7 +84,7 @@ class HierarchicalAllocator final { ET_CHECK_MSG(n_allocators <= kSpanArraySize, "n_allocators %" PRIu32 " > %zu", n_allocators, kSpanArraySize); - for (uint32_t i = 0; i < n_allocators; ++i) { + for (const auto i : c10::irange(n_allocators)) { span_array_[i] = Span(allocators[i].base_address(), allocators[i].size()); } diff --git a/third-party/include/executorch/runtime/core/memory_allocator.h b/third-party/include/executorch/runtime/core/memory_allocator.h index 80bdd1503f..256df7307f 100644 --- a/third-party/include/executorch/runtime/core/memory_allocator.h +++ b/third-party/include/executorch/runtime/core/memory_allocator.h @@ -186,170 +186,6 @@ class MemoryAllocator { int32_t prof_id_ = -1; }; -#if ET_HAVE_GNU_STATEMENT_EXPRESSIONS -/** - * Tries allocating from the specified MemoryAllocator*. - * - * - On success, returns a pointer to the allocated buffer. - * - On failure, executes the provided code block, which must return or panic. - * - * Example: - * @code - * char* buf = ET_TRY_ALLOCATE_OR( - * memory_allocator, bufsize, { - * *out_err = Error::MemoryAllocationFailed; - * return nullopt; - * }); - * @endcode - */ -#define ET_TRY_ALLOCATE_OR(memory_allocator__, nbytes__, ...) \ - ({ \ - void *et_try_allocate_result = memory_allocator__->allocate(nbytes__); \ - if (et_try_allocate_result == nullptr && nbytes__ > 0) { \ - __VA_ARGS__ \ - /* The args must return. */ \ - ET_UNREACHABLE(); \ - } \ - et_try_allocate_result; \ - }) - -/** - * Tries allocating an instance of type__ from the specified MemoryAllocator*. - * - * - On success, returns a pointer to the allocated buffer. Note that the memory - * will not be initialized. - * - On failure, executes the provided code block, which must return or panic. - * - * Example: - * @code - * char* buf = ET_TRY_ALLOCATE_INSTANCE_OR( - * memory_allocator, - * MyType, - * { *out_err = Error::MemoryAllocationFailed; return nullopt; }); - * @endcode - */ -#define ET_TRY_ALLOCATE_INSTANCE_OR(memory_allocator__, type__, ...) \ - ({ \ - type__ *et_try_allocate_result = \ - memory_allocator__->allocateInstance(); \ - if (et_try_allocate_result == nullptr) { \ - __VA_ARGS__ \ - /* The args must return. */ \ - ET_UNREACHABLE(); \ - } \ - et_try_allocate_result; \ - }) - -/** - * Tries allocating multiple elements of a given type from the specified - * MemoryAllocator*. - * - * - On success, returns a pointer to the allocated buffer. - * - On failure, executes the provided code block, which must return or panic. - * - * Example: - * @code - * Tensor* tensor_list = ET_TRY_ALLOCATE_LIST_OR( - * memory_allocator, Tensor, num_tensors, { - * *out_err = Error::MemoryAllocationFailed; - * return nullopt; - * }); - * @endcode - */ -#define ET_TRY_ALLOCATE_LIST_OR(memory_allocator__, type__, nelem__, ...) \ - ({ \ - type__ *et_try_allocate_result = \ - memory_allocator__->allocateList(nelem__); \ - if (et_try_allocate_result == nullptr && nelem__ > 0) { \ - __VA_ARGS__ \ - /* The args must return. */ \ - ET_UNREACHABLE(); \ - } \ - et_try_allocate_result; \ - }) -#else // !ET_HAVE_GNU_STATEMENT_EXPRESSIONS -/** - * The recommended alternative for statement expression-incompatible compilers - * is to directly allocate the memory. - * e.g. memory_allocator__->allocate(nbytes__); - */ -#define ET_TRY_ALLOCATE_OR(memory_allocator__, nbytes__, ...) \ - static_assert(false, "ET_TRY_ALLOCATE_OR uses statement expressions and \ - thus is not available for use with this compiler."); - -/** - * The recommended alternative for statement expression-incompatible compilers - * is to directly allocate the memory. - * e.g. memory_allocator__->allocateInstance(); - */ -#define ET_TRY_ALLOCATE_INSTANCE_OR(memory_allocator__, type__, ...) \ - static_assert(false, "ET_TRY_ALLOCATE_INSTANCE_OR uses statement \ - expressions and thus is not available for use with this compiler."); - -/** - * The recommended alternative for statement expression-incompatible compilers - * is to directly use allocate the memory. - * e.g. memory_allocator__->allocateList(nelem__); - */ -#define ET_TRY_ALLOCATE_LIST_OR(memory_allocator__, type__, nelem__, ...) \ - static_assert(false, "ET_TRY_ALLOCATE_LIST_OR uses statement \ - expressions and thus is not available for use with this compiler."); -#endif // !ET_HAVE_GNU_STATEMENT_EXPRESSIONS - -/** - * Tries allocating from the specified MemoryAllocator*. - * - * - On success, returns a pointer to the allocated buffer. - * - On failure, returns `Error::MemoryAllocationFailed` from the calling - * function, which must be declared to return `executorch::runtime::Error`. - * - * Example: - * @code - * char* buf = ET_ALLOCATE_OR_RETURN_ERROR(memory_allocator, bufsize); - * @endcode - */ -#define ET_ALLOCATE_OR_RETURN_ERROR(memory_allocator__, nbytes__) \ - ET_TRY_ALLOCATE_OR(memory_allocator__, nbytes__, { \ - return ::executorch::runtime::Error::MemoryAllocationFailed; \ - }) - -/** - * Tries allocating an instance of type__ from the specified MemoryAllocator*. - * - * - On success, returns a pointer to the allocated buffer. Note that the memory - * will not be initialized. - * - On failure, returns `Error::MemoryAllocationFailed` from the calling - * function, which must be declared to return `executorch::runtime::Error`. - * - * Example: - * @code - * char* buf = ET_ALLOCATE_INSTANCE_OR_RETURN_ERROR(memory_allocator, MyType); - * @endcode - */ -#define ET_ALLOCATE_INSTANCE_OR_RETURN_ERROR(memory_allocator__, type__) \ - ET_TRY_ALLOCATE_INSTANCE_OR(memory_allocator__, type__, { \ - return ::executorch::runtime::Error::MemoryAllocationFailed; \ - }) - -/** - * Tries allocating multiple elements of a given type from the specified - * MemoryAllocator*. - * - * - On success, returns a pointer to the allocated buffer. - * - On failure, returns `Error::MemoryAllocationFailed` from the calling - * function, which must be declared to return `executorch::runtime::Error`. - * - * Example: - * @code - * Tensor* tensor_list = ET_ALLOCATE_LIST_OR_RETURN_ERROR( - * memory_allocator, Tensor, num_tensors); - * @endcode - */ -#define ET_ALLOCATE_LIST_OR_RETURN_ERROR(memory_allocator__, type__, nelem__) \ - ET_TRY_ALLOCATE_LIST_OR(memory_allocator__, type__, nelem__, { \ - return ::executorch::runtime::Error::MemoryAllocationFailed; \ - }) - } // namespace runtime } // namespace executorch diff --git a/third-party/include/executorch/runtime/core/named_data_map.h b/third-party/include/executorch/runtime/core/named_data_map.h new file mode 100644 index 0000000000..48a311cf22 --- /dev/null +++ b/third-party/include/executorch/runtime/core/named_data_map.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#ifdef __GNUC__ +// Disable -Wdeprecated-declarations, as some builds use 'Werror'. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +#include +#include +#include +#include +#include +#include + +namespace executorch { +namespace runtime { + +/** + * Interface to access and retrieve data via name. + * See executorch/extension/flat_tensor/ for an example. + */ +class ET_EXPERIMENTAL NamedDataMap { +public: + virtual ~NamedDataMap() = default; + /** + * Get metadata by key. + * + * @param key The name of the tensor. + * @return Result containing TensorLayout with tensor metadata. + */ + ET_NODISCARD virtual Result + get_metadata(const char *key) const = 0; + /** + * Get data by key. + * + * @param key Name of the data. + * @return Result containing a FreeableBuffer with the tensor data. + */ + ET_NODISCARD virtual Result + get_data(const char *key) const = 0; + + /** + * Loads data corresponding to the key into the provided buffer. + * + * @param key The name of the data. + * @param size The number of bytes to load. Use `get_metadata` to retrieve the + * size of the data for a given key. + * @param buffer The buffer to load the data into. Must point to at least + * `size` bytes of memory. + * @returns an Error indicating if the load was successful. + */ + ET_NODISCARD virtual Error load_data_into(const char *key, void *buffer, + size_t size) const = 0; + + /** + * Get the number of keys in the NamedDataMap. + * + * @return Result containing the number of keys. + */ + ET_NODISCARD virtual Result get_num_keys() const = 0; + + /** + * Get the key at the given index. + * + * @param index The index of the key to retrieve. + * @return Result containing the key at the given index. Note: the returned + * pointer is only valid for the lifetime of the DataMap. + */ + ET_NODISCARD virtual Result get_key(size_t index) const = 0; +}; + +} // namespace runtime +} // namespace executorch + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/third-party/include/executorch/runtime/core/portable_type/bfloat16.h b/third-party/include/executorch/runtime/core/portable_type/bfloat16.h index 2ae42a8ec7..233d571478 100644 --- a/third-party/include/executorch/runtime/core/portable_type/bfloat16.h +++ b/third-party/include/executorch/runtime/core/portable_type/bfloat16.h @@ -8,254 +8,15 @@ #pragma once -#include -#include -#include -#include -#include - -namespace executorch { -namespace runtime { -namespace etensor { +#include +namespace executorch::runtime::etensor { +using c10::BFloat16; namespace internal { -inline float f32_from_bits(uint16_t src) { - float res = 0; - uint32_t tmp = src; - tmp <<= 16; - std::memcpy(&res, &tmp, sizeof(tmp)); - return res; -} - -inline uint16_t round_to_nearest_even(float src) { - if (std::isnan(src)) { - return UINT16_C(0x7FC0); - } - uint32_t U32 = 0; - std::memcpy(&U32, &src, sizeof(U32)); - uint32_t rounding_bias = ((U32 >> 16) & 1) + UINT32_C(0x7FFF); - return static_cast((U32 + rounding_bias) >> 16); -} +using c10::detail::f32_from_bits; +using c10::detail::round_to_nearest_even; } // namespace internal - -/** - * The "brain floating-point" type, compatible with c10/util/BFloat16.h from - * pytorch core. - * - * This representation uses 1 bit for the sign, 8 bits for the exponent and 7 - * bits for the mantissa. - */ -struct alignas(2) BFloat16 { - uint16_t x; - - BFloat16() = default; - struct from_bits_t {}; - static constexpr from_bits_t from_bits() { return from_bits_t(); } - - constexpr BFloat16(unsigned short bits, from_bits_t) : x(bits) {} - /* implicit */ BFloat16(float value) - : x(internal::round_to_nearest_even(value)) {} - operator float() const { return internal::f32_from_bits(x); } -}; - -inline std::ostream &operator<<(std::ostream &out, const BFloat16 &value) { - out << (float)value; - return out; -} - -/// Arithmetic - -inline BFloat16 operator+(const BFloat16 &a, const BFloat16 &b) { - return static_cast(a) + static_cast(b); -} - -inline BFloat16 operator-(const BFloat16 &a, const BFloat16 &b) { - return static_cast(a) - static_cast(b); -} - -inline BFloat16 operator*(const BFloat16 &a, const BFloat16 &b) { - return static_cast(a) * static_cast(b); -} - -inline BFloat16 operator/(const BFloat16 &a, const BFloat16 &b) { - return static_cast(a) / static_cast(b); -} - -inline BFloat16 operator-(const BFloat16 &a) { return -static_cast(a); } - -inline BFloat16 &operator+=(BFloat16 &a, const BFloat16 &b) { - a = a + b; - return a; -} - -inline BFloat16 &operator-=(BFloat16 &a, const BFloat16 &b) { - a = a - b; - return a; -} - -inline BFloat16 &operator*=(BFloat16 &a, const BFloat16 &b) { - a = a * b; - return a; -} - -inline BFloat16 &operator/=(BFloat16 &a, const BFloat16 &b) { - a = a / b; - return a; -} - -inline BFloat16 &operator|(BFloat16 &a, const BFloat16 &b) { - a.x = a.x | b.x; - return a; -} - -inline BFloat16 &operator^(BFloat16 &a, const BFloat16 &b) { - a.x = a.x ^ b.x; - return a; -} - -inline BFloat16 &operator&(BFloat16 &a, const BFloat16 &b) { - a.x = a.x & b.x; - return a; -} - -/// Arithmetic with floats - -inline float operator+(BFloat16 a, float b) { - return static_cast(a) + b; -} -inline float operator-(BFloat16 a, float b) { - return static_cast(a) - b; -} -inline float operator*(BFloat16 a, float b) { - return static_cast(a) * b; -} -inline float operator/(BFloat16 a, float b) { - return static_cast(a) / b; -} - -inline float operator+(float a, BFloat16 b) { - return a + static_cast(b); -} -inline float operator-(float a, BFloat16 b) { - return a - static_cast(b); -} -inline float operator*(float a, BFloat16 b) { - return a * static_cast(b); -} -inline float operator/(float a, BFloat16 b) { - return a / static_cast(b); -} - -inline float &operator+=(float &a, const BFloat16 &b) { - return a += static_cast(b); -} -inline float &operator-=(float &a, const BFloat16 &b) { - return a -= static_cast(b); -} -inline float &operator*=(float &a, const BFloat16 &b) { - return a *= static_cast(b); -} -inline float &operator/=(float &a, const BFloat16 &b) { - return a /= static_cast(b); -} - -/// Arithmetic with doubles - -inline double operator+(BFloat16 a, double b) { - return static_cast(a) + b; -} -inline double operator-(BFloat16 a, double b) { - return static_cast(a) - b; -} -inline double operator*(BFloat16 a, double b) { - return static_cast(a) * b; -} -inline double operator/(BFloat16 a, double b) { - return static_cast(a) / b; -} - -inline double operator+(double a, BFloat16 b) { - return a + static_cast(b); -} -inline double operator-(double a, BFloat16 b) { - return a - static_cast(b); -} -inline double operator*(double a, BFloat16 b) { - return a * static_cast(b); -} -inline double operator/(double a, BFloat16 b) { - return a / static_cast(b); -} - -/// Arithmetic with ints - -inline BFloat16 operator+(BFloat16 a, int b) { - return a + static_cast(b); -} -inline BFloat16 operator-(BFloat16 a, int b) { - return a - static_cast(b); -} -inline BFloat16 operator*(BFloat16 a, int b) { - return a * static_cast(b); -} -inline BFloat16 operator/(BFloat16 a, int b) { - return a / static_cast(b); -} - -inline BFloat16 operator+(int a, BFloat16 b) { - return static_cast(a) + b; -} -inline BFloat16 operator-(int a, BFloat16 b) { - return static_cast(a) - b; -} -inline BFloat16 operator*(int a, BFloat16 b) { - return static_cast(a) * b; -} -inline BFloat16 operator/(int a, BFloat16 b) { - return static_cast(a) / b; -} - -//// Arithmetic with int64_t - -inline BFloat16 operator+(BFloat16 a, int64_t b) { - return a + static_cast(b); -} -inline BFloat16 operator-(BFloat16 a, int64_t b) { - return a - static_cast(b); -} -inline BFloat16 operator*(BFloat16 a, int64_t b) { - return a * static_cast(b); -} -inline BFloat16 operator/(BFloat16 a, int64_t b) { - return a / static_cast(b); -} - -inline BFloat16 operator+(int64_t a, BFloat16 b) { - return static_cast(a) + b; -} -inline BFloat16 operator-(int64_t a, BFloat16 b) { - return static_cast(a) - b; -} -inline BFloat16 operator*(int64_t a, BFloat16 b) { - return static_cast(a) * b; -} -inline BFloat16 operator/(int64_t a, BFloat16 b) { - return static_cast(a) / b; -} - -// Overloading < and > operators, because std::max and std::min use them. - -inline bool operator>(BFloat16 &lhs, BFloat16 &rhs) { - return float(lhs) > float(rhs); -} - -inline bool operator<(BFloat16 &lhs, BFloat16 &rhs) { - return float(lhs) < float(rhs); -} - -} // namespace etensor -} // namespace runtime -} // namespace executorch +} // namespace executorch::runtime::etensor namespace torch { namespace executor { @@ -264,73 +25,3 @@ namespace executor { using ::executorch::runtime::etensor::BFloat16; } // namespace executor } // namespace torch - -namespace std { - -template <> class numeric_limits { -public: - static constexpr bool is_signed = true; - static constexpr bool is_specialized = true; - static constexpr bool is_integer = false; - static constexpr bool is_exact = false; - static constexpr bool has_infinity = true; - static constexpr bool has_quiet_NaN = true; - static constexpr bool has_signaling_NaN = true; - static constexpr auto has_denorm = numeric_limits::has_denorm; - static constexpr auto has_denorm_loss = - numeric_limits::has_denorm_loss; - static constexpr auto round_style = numeric_limits::round_style; - static constexpr bool is_iec559 = false; - static constexpr bool is_bounded = true; - static constexpr bool is_modulo = false; - static constexpr int digits = 8; - static constexpr int digits10 = 2; - static constexpr int max_digits10 = 4; - static constexpr int radix = 2; - static constexpr int min_exponent = -125; - static constexpr int min_exponent10 = -37; - static constexpr int max_exponent = 128; - static constexpr int max_exponent10 = 38; - static constexpr auto traps = numeric_limits::traps; - static constexpr auto tinyness_before = - numeric_limits::tinyness_before; - - static constexpr torch::executor::BFloat16 min() { - return torch::executor::BFloat16(0x0080, - torch::executor::BFloat16::from_bits()); - } - static constexpr torch::executor::BFloat16 lowest() { - return torch::executor::BFloat16(0xFF7F, - torch::executor::BFloat16::from_bits()); - } - static constexpr torch::executor::BFloat16 max() { - return torch::executor::BFloat16(0x7F7F, - torch::executor::BFloat16::from_bits()); - } - static constexpr torch::executor::BFloat16 epsilon() { - return torch::executor::BFloat16(0x3C00, - torch::executor::BFloat16::from_bits()); - } - static constexpr torch::executor::BFloat16 round_error() { - return torch::executor::BFloat16(0x3F00, - torch::executor::BFloat16::from_bits()); - } - static constexpr torch::executor::BFloat16 infinity() { - return torch::executor::BFloat16(0x7F80, - torch::executor::BFloat16::from_bits()); - } - static constexpr torch::executor::BFloat16 quiet_NaN() { - return torch::executor::BFloat16(0x7FC0, - torch::executor::BFloat16::from_bits()); - } - static constexpr torch::executor::BFloat16 signaling_NaN() { - return torch::executor::BFloat16(0x7F80, - torch::executor::BFloat16::from_bits()); - } - static constexpr torch::executor::BFloat16 denorm_min() { - return torch::executor::BFloat16(0x0001, - torch::executor::BFloat16::from_bits()); - } -}; - -} // namespace std diff --git a/third-party/include/executorch/runtime/core/portable_type/bfloat16_math.h b/third-party/include/executorch/runtime/core/portable_type/bfloat16_math.h index 3f6fd40036..3f6bf14a46 100644 --- a/third-party/include/executorch/runtime/core/portable_type/bfloat16_math.h +++ b/third-party/include/executorch/runtime/core/portable_type/bfloat16_math.h @@ -11,247 +11,4 @@ #include #include -namespace std { - -template -struct is_reduced_floating_point - : std::integral_constant< - bool, std::is_same::value || - std::is_same::value> {}; - -template ::value, int>::type = 0> -inline T acos(T a) { - return std::acos(float(a)); -} -template ::value, int>::type = 0> -inline T asin(T a) { - return std::asin(float(a)); -} -template ::value, int>::type = 0> -inline T atan(T a) { - return std::atan(float(a)); -} -template ::value, int>::type = 0> -inline T atanh(T a) { - return std::atanh(float(a)); -} -template ::value, int>::type = 0> -inline T erf(T a) { - return std::erf(float(a)); -} -template ::value, int>::type = 0> -inline T erfc(T a) { - return std::erfc(float(a)); -} -template ::value, int>::type = 0> -inline T exp(T a) { - return std::exp(float(a)); -} -template ::value, int>::type = 0> -inline T expm1(T a) { - return std::expm1(float(a)); -} -template ::value, int>::type = 0> -inline bool isfinite(T a) { - return std::isfinite(float(a)); -} -template ::value, int>::type = 0> -inline T log(T a) { - return std::log(float(a)); -} -template ::value, int>::type = 0> -inline T log10(T a) { - return std::log10(float(a)); -} -template ::value, int>::type = 0> -inline T log1p(T a) { - return std::log1p(float(a)); -} -template ::value, int>::type = 0> -inline T log2(T a) { - return std::log2(float(a)); -} -template ::value, int>::type = 0> -inline T ceil(T a) { - return std::ceil(float(a)); -} -template ::value, int>::type = 0> -inline T cos(T a) { - return std::cos(float(a)); -} -template ::value, int>::type = 0> -inline T floor(T a) { - return std::floor(float(a)); -} -template ::value, int>::type = 0> -inline T nearbyint(T a) { - return std::nearbyint(float(a)); -} -template ::value, int>::type = 0> -inline T sin(T a) { - return std::sin(float(a)); -} -template ::value, int>::type = 0> -inline T tan(T a) { - return std::tan(float(a)); -} -template ::value, int>::type = 0> -inline T sinh(T a) { - return std::sinh(float(a)); -} -template ::value, int>::type = 0> -inline T cosh(T a) { - return std::cosh(float(a)); -} -template ::value, int>::type = 0> -inline T tanh(T a) { - return std::tanh(float(a)); -} -template ::value, int>::type = 0> -inline T trunc(T a) { - return std::trunc(float(a)); -} -template ::value, int>::type = 0> -inline T lgamma(T a) { - return std::lgamma(float(a)); -} -template ::value, int>::type = 0> -inline T sqrt(T a) { - return std::sqrt(float(a)); -} -template ::value, int>::type = 0> -inline T rsqrt(T a) { - return 1.0 / std::sqrt(float(a)); -} -template ::value, int>::type = 0> -inline T abs(T a) { - return std::abs(float(a)); -} -#if defined(_MSC_VER) && defined(__CUDACC__) -template ::value, int>::type = 0> -inline T pow(T a, double b) { - return std::pow(float(a), float(b)); -} -#else -template ::value, int>::type = 0> -inline T pow(T a, double b) { - return std::pow(float(a), b); -} -#endif -template ::value, int>::type = 0> -inline T pow(T a, T b) { - return std::pow(float(a), float(b)); -} -template ::value, int>::type = 0> -inline T fmod(T a, T b) { - return std::fmod(float(a), float(b)); -} - -/* - The following function is inspired from the implementation in `musl` - Link to License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT - ---------------------------------------------------------------------- - Copyright © 2005-2020 Rich Felker, et al. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---------------------------------------------------------------------- - */ -template ::value, int>::type = 0> -inline T nextafter(T from, T to) { - // Reference: - // https://git.musl-libc.org/cgit/musl/tree/src/math/nextafter.c - using int_repr_t = uint16_t; - constexpr uint8_t bits = 16; - union { - T f; - int_repr_t i; - } ufrom = {from}, uto = {to}; - - // get a mask to get the sign bit i.e. MSB - int_repr_t sign_mask = int_repr_t{1} << (bits - 1); - - // short-circuit: if either is NaN, return NaN - if (from != from || to != to) { - return from + to; - } - - // short-circuit: if they are exactly the same. - if (ufrom.i == uto.i) { - return from; - } - - // mask the sign-bit to zero i.e. positive - // equivalent to abs(x) - int_repr_t abs_from = ufrom.i & ~sign_mask; - int_repr_t abs_to = uto.i & ~sign_mask; - if (abs_from == 0) { - // if both are zero but with different sign, - // preserve the sign of `to`. - if (abs_to == 0) { - return to; - } - // smallest subnormal with sign of `to`. - ufrom.i = (uto.i & sign_mask) | int_repr_t{1}; - return ufrom.f; - } - - // if abs(from) > abs(to) or sign(from) != sign(to) - if (abs_from > abs_to || ((ufrom.i ^ uto.i) & sign_mask)) { - ufrom.i--; - } else { - ufrom.i++; - } - - return ufrom.f; -} - -} // namespace std +#include diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/macros/Export.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/macros/Export.h new file mode 100644 index 0000000000..771c869ae0 --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/macros/Export.h @@ -0,0 +1,163 @@ +#define C10_USING_CUSTOM_GENERATED_MACROS +#ifndef C10_MACROS_EXPORT_H_ +#define C10_MACROS_EXPORT_H_ + +/* Header file to define the common scaffolding for exported symbols. + * + * Export is by itself a quite tricky situation to deal with, and if you are + * hitting this file, make sure you start with the background here: + * - Linux: https://gcc.gnu.org/wiki/Visibility + * - Windows: + * https://docs.microsoft.com/en-us/cpp/cpp/dllexport-dllimport?view=vs-2017 + * + * Do NOT include this file directly. Instead, use c10/macros/Macros.h + */ + +// You do not need to edit this part of file unless you are changing the core +// pytorch export abstractions. +// +// This part defines the C10 core export and import macros. This is controlled +// by whether we are building shared libraries or not, which is determined +// during build time and codified in c10/core/cmake_macros.h. +// When the library is built as a shared lib, EXPORT and IMPORT will contain +// visibility attributes. If it is being built as a static lib, then EXPORT +// and IMPORT basically have no effect. + +// As a rule of thumb, you should almost NEVER mix static and shared builds for +// libraries that depend on c10. AKA, if c10 is built as a static library, we +// recommend everything dependent on c10 to be built statically. If c10 is built +// as a shared library, everything dependent on it should be built as shared. In +// the PyTorch project, all native libraries shall use the macro +// C10_BUILD_SHARED_LIB to check whether pytorch is building shared or static +// libraries. + +// For build systems that do not directly depend on CMake and directly build +// from the source directory (such as Buck), one may not have a cmake_macros.h +// file at all. In this case, the build system is responsible for providing +// correct macro definitions corresponding to the cmake_macros.h.in file. +// +// In such scenarios, one should define the macro +// C10_USING_CUSTOM_GENERATED_MACROS +// to inform this header that it does not need to include the cmake_macros.h +// file. + +#ifndef C10_USING_CUSTOM_GENERATED_MACROS +#include +#endif // C10_USING_CUSTOM_GENERATED_MACROS + +#ifdef _WIN32 +#define C10_HIDDEN +#if defined(C10_BUILD_SHARED_LIBS) +#define C10_EXPORT __declspec(dllexport) +#define C10_IMPORT __declspec(dllimport) +#else +#define C10_EXPORT +#define C10_IMPORT +#endif +#else // _WIN32 +#if defined(__GNUC__) +#define C10_EXPORT __attribute__((__visibility__("default"))) +#define C10_HIDDEN __attribute__((__visibility__("hidden"))) +#else // defined(__GNUC__) +#define C10_EXPORT +#define C10_HIDDEN +#endif // defined(__GNUC__) +#define C10_IMPORT C10_EXPORT +#endif // _WIN32 + +#ifdef NO_EXPORT +#undef C10_EXPORT +#define C10_EXPORT +#endif + +// Definition of an adaptive XX_API macro, that depends on whether you are +// building the library itself or not, routes to XX_EXPORT and XX_IMPORT. +// Basically, you will need to do this for each shared library that you are +// building, and the instruction is as follows: assuming that you are building +// a library called libawesome.so. You should: +// (1) for your cmake target (usually done by "add_library(awesome, ...)"), +// define a macro called AWESOME_BUILD_MAIN_LIB using +// target_compile_options. +// (2) define the AWESOME_API macro similar to the one below. +// And in the source file of your awesome library, use AWESOME_API to +// annotate public symbols. + +// Here, for the C10 library, we will define the macro C10_API for both import +// and export. + +// This one is being used by libc10.so +#ifdef C10_BUILD_MAIN_LIB +#define C10_API C10_EXPORT +#else +#define C10_API C10_IMPORT +#endif + +// This one is being used by libtorch.so +#ifdef CAFFE2_BUILD_MAIN_LIB +#define TORCH_API C10_EXPORT +#else +#define TORCH_API C10_IMPORT +#endif + +// You may be wondering: Whose brilliant idea was it to split torch_cuda into +// two pieces with confusing names? +// Once upon a time, there _was_ only TORCH_CUDA_API. All was happy until we +// tried to compile PyTorch for CUDA 11.1, which ran into relocation marker +// issues when linking big binaries. +// (https://github.com/pytorch/pytorch/issues/39968) We had two choices: +// (1) Stop supporting so many GPU architectures +// (2) Do something else +// We chose #2 and decided to split the behemoth that was torch_cuda into two +// smaller libraries, one with most of the core kernel functions (torch_cuda_cu) +// and the other that had..well..everything else (torch_cuda_cpp). The idea was +// this: instead of linking our static libraries (like the hefty +// libcudnn_static.a) with another huge library, torch_cuda, and run into pesky +// relocation marker issues, we could link our static libraries to a smaller +// part of torch_cuda (torch_cuda_cpp) and avoid the issues. + +// libtorch_cuda_cu.so +#ifdef TORCH_CUDA_CU_BUILD_MAIN_LIB +#define TORCH_CUDA_CU_API C10_EXPORT +#elif defined(BUILD_SPLIT_CUDA) +#define TORCH_CUDA_CU_API C10_IMPORT +#endif + +// libtorch_cuda_cpp.so +#ifdef TORCH_CUDA_CPP_BUILD_MAIN_LIB +#define TORCH_CUDA_CPP_API C10_EXPORT +#elif defined(BUILD_SPLIT_CUDA) +#define TORCH_CUDA_CPP_API C10_IMPORT +#endif + +// libtorch_cuda.so (where torch_cuda_cu and torch_cuda_cpp are a part of the +// same api) +#ifdef TORCH_CUDA_BUILD_MAIN_LIB +#define TORCH_CUDA_CPP_API C10_EXPORT +#define TORCH_CUDA_CU_API C10_EXPORT +#elif !defined(BUILD_SPLIT_CUDA) +#define TORCH_CUDA_CPP_API C10_IMPORT +#define TORCH_CUDA_CU_API C10_IMPORT +#endif + +#if defined(TORCH_HIP_BUILD_MAIN_LIB) +#define TORCH_HIP_CPP_API C10_EXPORT +#define TORCH_HIP_API C10_EXPORT +#else +#define TORCH_HIP_CPP_API C10_IMPORT +#define TORCH_HIP_API C10_IMPORT +#endif + +#if defined(TORCH_XPU_BUILD_MAIN_LIB) +#define TORCH_XPU_API C10_EXPORT +#else +#define TORCH_XPU_API C10_IMPORT +#endif + +// Enums only need to be exported on windows for non-CUDA files +#if defined(_WIN32) && defined(__CUDACC__) +#define C10_API_ENUM C10_API +#else +#define C10_API_ENUM +#endif + +#endif // C10_MACROS_MACROS_H_ diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h new file mode 100644 index 0000000000..d46e2a369d --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h @@ -0,0 +1,497 @@ +#define C10_USING_CUSTOM_GENERATED_MACROS +#ifndef C10_MACROS_MACROS_H_ +#define C10_MACROS_MACROS_H_ +#include + +/* Main entry for c10/macros. + * + * In your code, include c10/macros/Macros.h directly, instead of individual + * files in this folder. + */ + +// For build systems that do not directly depend on CMake and directly build +// from the source directory (such as Buck), one may not have a cmake_macros.h +// file at all. In this case, the build system is responsible for providing +// correct macro definitions corresponding to the cmake_macros.h.in file. +// +// In such scenarios, one should define the macro +// C10_USING_CUSTOM_GENERATED_MACROS +// to inform this header that it does not need to include the cmake_macros.h +// file. + +#ifndef C10_USING_CUSTOM_GENERATED_MACROS +#include +#endif // C10_USING_CUSTOM_GENERATED_MACROS + +#include + +#if defined(__clang__) +#define __ubsan_ignore_float_divide_by_zero__ \ + __attribute__((no_sanitize("float-divide-by-zero"))) +#define __ubsan_ignore_undefined__ __attribute__((no_sanitize("undefined"))) +#define __ubsan_ignore_signed_int_overflow__ \ + __attribute__((no_sanitize("signed-integer-overflow"))) +#define __ubsan_ignore_pointer_overflow__ \ + __attribute__((no_sanitize("pointer-overflow"))) +#define __ubsan_ignore_function__ __attribute__((no_sanitize("function"))) +#define __ubsan_ignore_float_cast_overflow__ \ + __attribute__((no_sanitize("float-cast-overflow"))) +#else +#define __ubsan_ignore_float_divide_by_zero__ +#define __ubsan_ignore_undefined__ +#define __ubsan_ignore_signed_int_overflow__ +#define __ubsan_ignore_pointer_overflow__ +#define __ubsan_ignore_function__ +#define __ubsan_ignore_float_cast_overflow__ +#endif + +// Detect address sanitizer as some stuff doesn't work with it +#undef C10_ASAN_ENABLED + +// for clang +#if defined(__has_feature) +#if ((__has_feature(address_sanitizer))) +#define C10_ASAN_ENABLED 1 +#endif +#endif + +// for gcc +#if defined(__SANITIZE_ADDRESS__) +#if __SANITIZE_ADDRESS__ +#if !defined(C10_ASAN_ENABLED) +#define C10_ASAN_ENABLED 1 +#endif +#endif +#endif + +#if !defined(C10_ASAN_ENABLED) +#define C10_ASAN_ENABLED 0 +#endif + +// Detect undefined-behavior sanitizer (UBSAN) +#undef C10_UBSAN_ENABLED + +// for clang or gcc >= 14 +// NB: gcc 14 adds support for Clang's __has_feature +// https://gcc.gnu.org/gcc-14/changes.html +// gcc < 14 doesn't have a macro for UBSAN +// (e.g. __SANITIZE_UNDEFINED__ does not exist in gcc) +// https://github.com/google/sanitizers/issues/765 +#if defined(__has_feature) +#if ((__has_feature(undefined_behavior_sanitizer))) +#define C10_UBSAN_ENABLED 1 +#endif +#endif + +#if !defined(C10_UBSAN_ENABLED) +#define C10_UBSAN_ENABLED 0 +#endif + +// Disable the copy and assignment operator for a class. Note that this will +// disable the usage of the class in std containers. +#define C10_DISABLE_COPY_AND_ASSIGN(classname) \ + classname(const classname &) = delete; \ + classname &operator=(const classname &) = delete + +#define C10_CONCATENATE_IMPL(s1, s2) s1##s2 +#define C10_CONCATENATE(s1, s2) C10_CONCATENATE_IMPL(s1, s2) + +#define C10_MACRO_EXPAND(args) args + +#define C10_STRINGIZE_IMPL(x) #x +#define C10_STRINGIZE(x) C10_STRINGIZE_IMPL(x) + +/** + * C10_ANONYMOUS_VARIABLE(str) introduces a new identifier which starts with + * str and ends with a unique number. + */ +#ifdef __COUNTER__ +#define C10_UID __COUNTER__ +#define C10_ANONYMOUS_VARIABLE(str) C10_CONCATENATE(str, __COUNTER__) +#else +#define C10_UID __LINE__ +#define C10_ANONYMOUS_VARIABLE(str) C10_CONCATENATE(str, __LINE__) +#endif + +#ifdef __has_cpp_attribute +#define C10_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +#define C10_HAS_CPP_ATTRIBUTE(x) (0) +#endif + +#ifndef FBCODE_CAFFE2 +/// DEPRECATED: Warn if a type or return value is discarded. +#define C10_NODISCARD [[nodiscard]] + +/// DEPRECATED: Suppress an unused variable. +#define C10_UNUSED [[maybe_unused]] +#endif + +#if !defined(__has_attribute) +#define __has_attribute(x) 0 +#endif + +// Direct port of LLVM_ATTRIBUTE_USED. +#if __has_attribute(used) +#define C10_USED __attribute__((__used__)) +#else +#define C10_USED +#endif + +#define C10_RESTRICT __restrict + +// Simply define the namespace, in case a dependent library want to refer to +// the c10 namespace but not any nontrivial files. +namespace c10 {} +namespace c10::cuda {} +namespace c10::hip {} +namespace c10::xpu {} + +// Since C10 is the core library for caffe2 (and aten), we will simply reroute +// all abstractions defined in c10 to be available in caffe2 as well. +// This is only for backwards compatibility. Please use the symbols from the +// c10 namespace where possible. +namespace caffe2 { +using namespace c10; +} +namespace at { +using namespace c10; +} +namespace at::cuda { +using namespace c10::cuda; +} // namespace at::cuda + +// WARNING!!! THIS IS A GIANT HACK!!! +// This line means you cannot simultaneously include c10/hip +// and c10/cuda and then use them from the at::cuda namespace. +// This is true in practice, because HIPIFY works inplace on +// files in ATen/cuda, so it assumes that c10::hip is available +// from at::cuda. This namespace makes that happen. When +// HIPIFY is no longer out-of-place, we can switch the cuda +// here to hip and everyone is happy. +namespace at::cuda { +using namespace c10::hip; +} // namespace at::cuda + +namespace at::xpu { +using namespace c10::xpu; +} // namespace at::xpu + +// C10_LIKELY/C10_UNLIKELY +// +// These macros provide parentheses, so you can use these macros as: +// +// if C10_LIKELY(some_expr) { +// ... +// } +// +// NB: static_cast to boolean is mandatory in C++, because __builtin_expect +// takes a long argument, which means you may trigger the wrong conversion +// without it. +// +#if defined(__GNUC__) || defined(__ICL) || defined(__clang__) +#define C10_LIKELY(expr) (__builtin_expect(static_cast(expr), 1)) +#define C10_UNLIKELY(expr) (__builtin_expect(static_cast(expr), 0)) +#else +#define C10_LIKELY(expr) (expr) +#define C10_UNLIKELY(expr) (expr) +#endif + +/// C10_NOINLINE - Functions whose declaration is annotated with this will not +/// be inlined. +#ifdef __GNUC__ +#define C10_NOINLINE __attribute__((noinline)) +#elif _MSC_VER +#define C10_NOINLINE __declspec(noinline) +#else +#define C10_NOINLINE +#endif + +#if defined(_MSC_VER) +#define C10_ALWAYS_INLINE __forceinline +#elif __has_attribute(always_inline) || defined(__GNUC__) +#define C10_ALWAYS_INLINE __attribute__((__always_inline__)) inline +#else +#define C10_ALWAYS_INLINE inline +#endif + +// Unlike C10_ALWAYS_INLINE, C10_ALWAYS_INLINE_ATTRIBUTE can be used +// on a lambda. +#if defined(_MSC_VER) +// MSVC 14.39 is reasonably recent and doesn't like +// [[msvc::forceinline]] on a lambda, so don't try to use it. +#define C10_ALWAYS_INLINE_ATTRIBUTE +#elif __has_attribute(always_inline) || defined(__GNUC__) +#define C10_ALWAYS_INLINE_ATTRIBUTE __attribute__((__always_inline__)) +#else +#define C10_ALWAYS_INLINE_ATTRIBUTE +#endif + +#if defined(_MSC_VER) +#define C10_ATTR_VISIBILITY_HIDDEN +#elif defined(__GNUC__) +#define C10_ATTR_VISIBILITY_HIDDEN __attribute__((__visibility__("hidden"))) +#else +#define C10_ATTR_VISIBILITY_HIDDEN +#endif + +#define C10_ERASE C10_ALWAYS_INLINE C10_ATTR_VISIBILITY_HIDDEN + +#include + +#ifdef __HIPCC__ +// Unlike CUDA, HIP requires a HIP header to be included for __host__ to work. +// We do this #include here so that C10_HOST_DEVICE and friends will Just Work. +// See https://github.com/ROCm-Developer-Tools/HIP/issues/441 +#include +#endif + +#if defined(__CUDACC__) || defined(__HIPCC__) +// Designates functions callable from the host (CPU) and the device (GPU) +#define C10_HOST_DEVICE __host__ __device__ +#define C10_DEVICE __device__ +#define C10_HOST __host__ +// constants from +// (https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical-specifications) +// The maximum number of threads per multiprocessor is 1024 for Turing +// architecture (7.5), 1536 for Geforce Ampere (8.6)/Jetson Orin (8.7), and +// 2048 for all other architectures. You'll get warnings if you exceed these +// constants. Hence, the following macros adjust the input values from the user +// to resolve potential warnings. +#if __CUDA_ARCH__ == 750 +constexpr uint32_t CUDA_MAX_THREADS_PER_SM = 1024; +#elif __CUDA_ARCH__ == 860 || __CUDA_ARCH__ == 870 || __CUDA_ARCH__ == 890 +constexpr uint32_t CUDA_MAX_THREADS_PER_SM = 1536; +#else +constexpr uint32_t CUDA_MAX_THREADS_PER_SM = 2048; +#endif +// CUDA_MAX_THREADS_PER_BLOCK is same for all architectures currently +constexpr uint32_t CUDA_MAX_THREADS_PER_BLOCK = 1024; +// CUDA_THREADS_PER_BLOCK_FALLBACK is the "canonical fallback" choice of block +// size. 256 is a good number for this fallback and should give good occupancy +// and versatility across all architectures. +constexpr uint32_t CUDA_THREADS_PER_BLOCK_FALLBACK = 256; +// NOTE: if you are thinking of constexpr-ify the inputs to launch bounds, it +// turns out that although __launch_bounds__ can take constexpr, it +// can't take a constexpr that has anything to do with templates. +// Currently we use launch_bounds that depend on template arguments in +// Loops.cuh, Reduce.cuh and LossCTC.cuh. Hence, C10_MAX_THREADS_PER_BLOCK +// and C10_MIN_BLOCKS_PER_SM are kept as macros. +// Suppose you were planning to write __launch_bounds__(a, b), based on your +// performance tuning on a modern GPU. Instead, you should write +// __launch_bounds__(C10_MAX_THREADS_PER_BLOCK(a), C10_MIN_BLOCKS_PER_SM(a, b)), +// which will also properly respect limits on old architectures. +#define C10_MAX_THREADS_PER_BLOCK(val) \ + (((val) <= CUDA_MAX_THREADS_PER_BLOCK) ? (val) \ + : CUDA_THREADS_PER_BLOCK_FALLBACK) +#define C10_MIN_BLOCKS_PER_SM(threads_per_block, blocks_per_sm) \ + ((((threads_per_block) * (blocks_per_sm) <= CUDA_MAX_THREADS_PER_SM) \ + ? (blocks_per_sm) \ + : ((CUDA_MAX_THREADS_PER_SM + (threads_per_block) - 1) / \ + (threads_per_block)))) +// C10_LAUNCH_BOUNDS is analogous to __launch_bounds__ +#define C10_LAUNCH_BOUNDS_0 \ + __launch_bounds__(256, \ + 4) // default launch bounds that should give good occupancy + // and versatility across all architectures. +#define C10_LAUNCH_BOUNDS_1(max_threads_per_block) \ + __launch_bounds__((C10_MAX_THREADS_PER_BLOCK((max_threads_per_block)))) +#define C10_LAUNCH_BOUNDS_2(max_threads_per_block, min_blocks_per_sm) \ + __launch_bounds__( \ + (C10_MAX_THREADS_PER_BLOCK((max_threads_per_block))), \ + (C10_MIN_BLOCKS_PER_SM((max_threads_per_block), (min_blocks_per_sm)))) +#else +#define C10_HOST_DEVICE +#define C10_HOST +#define C10_DEVICE +#endif + +#if defined(USE_ROCM) +#define C10_HIP_HOST_DEVICE __host__ __device__ +#else +#define C10_HIP_HOST_DEVICE +#endif + +#if defined(USE_ROCM) +#define C10_WARP_SIZE warpSize // = 64 or 32 (Defined in hip_runtime.h) +#else +#define C10_WARP_SIZE 32 +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +#define __func__ __FUNCTION__ +#endif + +// CUDA_KERNEL_ASSERT checks the assertion +// even when NDEBUG is defined. This is useful for important assertions in CUDA +// code that would otherwise be suppressed when building Release. +#if defined(__ANDROID__) || defined(__APPLE__) || defined(__FreeBSD__) +// Those platforms do not support assert() +#define CUDA_KERNEL_ASSERT(cond) +#define CUDA_KERNEL_ASSERT_MSG(cond, msg) +#define SYCL_KERNEL_ASSERT(cond) +#elif defined(_MSC_VER) +#if defined(NDEBUG) +extern "C" { +C10_IMPORT +#if defined(__SYCL_DEVICE_ONLY__) +extern SYCL_EXTERNAL void _wassert(const wchar_t *wexpr, const wchar_t *wfile, + unsigned line); +#else +#if defined(__CUDA_ARCH__) +__host__ __device__ +#endif // __CUDA_ARCH__ + void + _wassert(wchar_t const *_Message, wchar_t const *_File, unsigned _Line); +#endif // __SYCL_DEVICE_ONLY__ +} +#endif // NDEBUG +#define CUDA_KERNEL_ASSERT(cond) \ + if (C10_UNLIKELY(!(cond))) { \ + (void)(_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), \ + static_cast(__LINE__)), \ + 0); \ + } +// TODO: This doesn't assert the message because I (chilli) couldn't figure out +// a nice way to convert a char* to a wchar_t* +#define CUDA_KERNEL_ASSERT_MSG(cond, msg) \ + if (C10_UNLIKELY(!(cond))) { \ + (void)(_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), \ + static_cast(__LINE__)), \ + 0); \ + } +#define SYCL_KERNEL_ASSERT(cond) \ + if (C10_UNLIKELY(!(cond))) { \ + (void)(_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), \ + static_cast(__LINE__)), \ + 0); \ + } +#else // __APPLE__, _MSC_VER +#if defined(NDEBUG) +extern "C" { +#if defined(__SYCL_DEVICE_ONLY__) +extern SYCL_EXTERNAL void __assert_fail(const char *expr, const char *file, + unsigned int line, const char *func); +#else // __SYCL_DEVICE_ONLY__ +#if (defined(__CUDA_ARCH__) && !(defined(__clang__) && defined(__CUDA__))) +// CUDA supports __assert_fail function which are common for both device +// and host side code. +__host__ __device__ +#endif + + // This forward declaration matching the declaration of __assert_fail + // exactly how it is in glibc in case parts of the program are compiled with + // different NDEBUG settings. Otherwise we might get 'ambiguous declaration' + // error. Note: On ROCm - this declaration serves for host side compilation. + void + __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function) noexcept __attribute__((__noreturn__)); + +#endif // __SYCL_DEVICE_ONLY__ +} +#endif // NDEBUG +// ROCm disable kernel assert by default +#if !defined(C10_USE_ROCM_KERNEL_ASSERT) and defined(USE_ROCM) +#define CUDA_KERNEL_ASSERT(cond) +#define CUDA_KERNEL_ASSERT_MSG(cond, msg) +#define SYCL_KERNEL_ASSERT(cond) +#else +#define CUDA_KERNEL_ASSERT(cond) \ + if (C10_UNLIKELY(!(cond))) { \ + __assert_fail(#cond, __FILE__, static_cast(__LINE__), \ + __func__); \ + } +#define CUDA_KERNEL_ASSERT_MSG(cond, msg) \ + if (C10_UNLIKELY(!(cond))) { \ + __assert_fail(msg, __FILE__, static_cast(__LINE__), \ + __func__); \ + } +#define SYCL_KERNEL_ASSERT(cond) \ + if (C10_UNLIKELY(!(cond))) { \ + __assert_fail(#cond, __FILE__, static_cast(__LINE__), \ + __func__); \ + } +#endif // C10_USE_ROCM_KERNEL_ASSERT and USE_ROCM +#endif // __APPLE__ + +#ifdef __APPLE__ +#include +#endif + +#if defined(__ANDROID__) +#define C10_ANDROID 1 +#define C10_MOBILE 1 +#elif (defined(__APPLE__) && \ + (TARGET_IPHONE_SIMULATOR || TARGET_OS_SIMULATOR || TARGET_OS_IPHONE)) +#define C10_IOS 1 +#define C10_MOBILE 1 +#endif // ANDROID / IOS + +#if defined(C10_MOBILE) && C10_MOBILE +#define C10_ALWAYS_INLINE_UNLESS_MOBILE inline +#else +#define C10_ALWAYS_INLINE_UNLESS_MOBILE C10_ALWAYS_INLINE +#endif + +#if !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED) +#define CONSTEXPR_EXCEPT_WIN_CUDA constexpr +#define C10_HOST_CONSTEXPR_EXCEPT_WIN_CUDA constexpr + +#define STATIC_CONSTEXPR_STR_INL_EXCEPT_WIN_CUDA(field, val) \ + static constexpr const char field[] = val; +#define STATIC_CONST_STR_OUT_OF_LINE_FOR_WIN_CUDA(cls, field, val) +#endif // !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED) + +#ifndef HAS_DEMANGLE +#if defined(__ANDROID__) || defined(_WIN32) || defined(__EMSCRIPTEN__) +#define HAS_DEMANGLE 0 +#elif defined(__APPLE__) && \ + (TARGET_IPHONE_SIMULATOR || TARGET_OS_SIMULATOR || TARGET_OS_IPHONE) +#define HAS_DEMANGLE 0 +#else +#define HAS_DEMANGLE 1 +#endif +#endif // HAS_DEMANGLE + +#define _C10_PRAGMA__(string) _Pragma(#string) +#define _C10_PRAGMA_(string) _C10_PRAGMA__(string) + +#ifdef __clang__ +#define C10_CLANG_DIAGNOSTIC_PUSH() _Pragma("clang diagnostic push") +#define C10_CLANG_DIAGNOSTIC_POP() _Pragma("clang diagnostic pop") +#define C10_CLANG_DIAGNOSTIC_IGNORE(flag) \ + _C10_PRAGMA_(clang diagnostic ignored flag) +#define C10_CLANG_HAS_WARNING(flag) __has_warning(flag) +#else +#define C10_CLANG_DIAGNOSTIC_PUSH() +#define C10_CLANG_DIAGNOSTIC_POP() +#define C10_CLANG_DIAGNOSTIC_IGNORE(flag) +#define C10_CLANG_HAS_WARNING(flag) 0 +#endif + +#ifdef __clang__ + +#define C10_DIAGNOSTIC_PUSH_AND_IGNORED_IF_DEFINED(warning) \ + _C10_PRAGMA_(clang diagnostic push) \ + _C10_PRAGMA_(clang diagnostic ignored "-Wunknown-warning-option") \ + _C10_PRAGMA_(clang diagnostic ignored warning) + +#define C10_DIAGNOSTIC_POP() _C10_PRAGMA_(clang diagnostic pop) + +#elif __GNUC__ + +#define C10_DIAGNOSTIC_PUSH_AND_IGNORED_IF_DEFINED(warning) \ + _C10_PRAGMA_(GCC diagnostic push) \ + _C10_PRAGMA_(GCC diagnostic ignored "-Wpragmas") \ + _C10_PRAGMA_(GCC diagnostic ignored warning) + +#define C10_DIAGNOSTIC_POP() _C10_PRAGMA_(GCC diagnostic pop) + +#else + +#define C10_DIAGNOSTIC_PUSH_AND_IGNORED_IF_DEFINED(warning) +#define C10_DIAGNOSTIC_POP() + +#endif + +#endif // C10_MACROS_MACROS_H_ diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h new file mode 100644 index 0000000000..d37a19d510 --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h @@ -0,0 +1,342 @@ +#pragma once + +#include +#include + +#include + +C10_CLANG_DIAGNOSTIC_PUSH() +#if C10_CLANG_HAS_WARNING("-Wimplicit-int-float-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") +#endif + +#if defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) +#if defined(CL_SYCL_LANGUAGE_VERSION) +#include // for SYCL 1.2.1 +#else +#include // for SYCL 2020 +#endif +#include +#endif + +namespace c10 { + +/// Constructors +inline C10_HOST_DEVICE BFloat16::BFloat16(float value) + : +#if defined(__CUDACC__) && !defined(USE_ROCM) && defined(__CUDA_ARCH__) && \ + __CUDA_ARCH__ >= 800 + x(__bfloat16_as_ushort(__float2bfloat16(value))) +#elif defined(__SYCL_DEVICE_ONLY__) && \ + defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) + x(c10::bit_cast(sycl::ext::oneapi::bfloat16(value))) +#else + // RNE by default + x(detail::round_to_nearest_even(value)) +#endif +{ +} + +/// Implicit conversions +inline C10_HOST_DEVICE BFloat16::operator float() const { +#if defined(__CUDACC__) && !defined(USE_ROCM) + return __bfloat162float(*reinterpret_cast(&x)); +#elif defined(__SYCL_DEVICE_ONLY__) && \ + defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) + return float(*reinterpret_cast(&x)); +#else + return detail::f32_from_bits(x); +#endif +} + +#if defined(__CUDACC__) && !defined(USE_ROCM) +inline C10_HOST_DEVICE BFloat16::BFloat16(const __nv_bfloat16 &value) { + x = *reinterpret_cast(&value); +} +inline C10_HOST_DEVICE BFloat16::operator __nv_bfloat16() const { + return *reinterpret_cast(&x); +} +#endif + +#if defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) +inline C10_HOST_DEVICE +BFloat16::BFloat16(const sycl::ext::oneapi::bfloat16 &value) { + x = *reinterpret_cast(&value); +} +inline C10_HOST_DEVICE BFloat16::operator sycl::ext::oneapi::bfloat16() const { + return *reinterpret_cast(&x); +} +#endif + +// CUDA intrinsics + +#if defined(__CUDACC__) || defined(__HIPCC__) +inline C10_DEVICE BFloat16 __ldg(const BFloat16 *ptr) { +#if !defined(USE_ROCM) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 + return __ldg(reinterpret_cast(ptr)); +#else + return *ptr; +#endif +} +#endif + +/// Arithmetic + +inline C10_HOST_DEVICE BFloat16 operator+(const BFloat16 &a, + const BFloat16 &b) { + return static_cast(a) + static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator-(const BFloat16 &a, + const BFloat16 &b) { + return static_cast(a) - static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator*(const BFloat16 &a, + const BFloat16 &b) { + return static_cast(a) * static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator/(const BFloat16 &a, const BFloat16 &b) + __ubsan_ignore_float_divide_by_zero__ { + return static_cast(a) / static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator-(const BFloat16 &a) { + return -static_cast(a); +} + +inline C10_HOST_DEVICE BFloat16 &operator+=(BFloat16 &a, const BFloat16 &b) { + a = a + b; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator-=(BFloat16 &a, const BFloat16 &b) { + a = a - b; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator*=(BFloat16 &a, const BFloat16 &b) { + a = a * b; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator/=(BFloat16 &a, const BFloat16 &b) { + a = a / b; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator|(BFloat16 &a, const BFloat16 &b) { + a.x = a.x | b.x; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator^(BFloat16 &a, const BFloat16 &b) { + a.x = a.x ^ b.x; + return a; +} + +inline C10_HOST_DEVICE BFloat16 &operator&(BFloat16 &a, const BFloat16 &b) { + a.x = a.x & b.x; + return a; +} + +/// Arithmetic with floats + +inline C10_HOST_DEVICE float operator+(BFloat16 a, float b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE float operator-(BFloat16 a, float b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE float operator*(BFloat16 a, float b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE float operator/(BFloat16 a, float b) { + return static_cast(a) / b; +} + +inline C10_HOST_DEVICE float operator+(float a, BFloat16 b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE float operator-(float a, BFloat16 b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE float operator*(float a, BFloat16 b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE float operator/(float a, BFloat16 b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE float &operator+=(float &a, const BFloat16 &b) { + return a += static_cast(b); +} +inline C10_HOST_DEVICE float &operator-=(float &a, const BFloat16 &b) { + return a -= static_cast(b); +} +inline C10_HOST_DEVICE float &operator*=(float &a, const BFloat16 &b) { + return a *= static_cast(b); +} +inline C10_HOST_DEVICE float &operator/=(float &a, const BFloat16 &b) { + return a /= static_cast(b); +} + +/// Arithmetic with doubles + +inline C10_HOST_DEVICE double operator+(BFloat16 a, double b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE double operator-(BFloat16 a, double b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE double operator*(BFloat16 a, double b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE double operator/(BFloat16 a, double b) { + return static_cast(a) / b; +} + +inline C10_HOST_DEVICE double operator+(double a, BFloat16 b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE double operator-(double a, BFloat16 b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE double operator*(double a, BFloat16 b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE double operator/(double a, BFloat16 b) { + return a / static_cast(b); +} + +/// Arithmetic with ints + +inline C10_HOST_DEVICE BFloat16 operator+(BFloat16 a, int b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator-(BFloat16 a, int b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator*(BFloat16 a, int b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator/(BFloat16 a, int b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator+(int a, BFloat16 b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE BFloat16 operator-(int a, BFloat16 b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE BFloat16 operator*(int a, BFloat16 b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE BFloat16 operator/(int a, BFloat16 b) { + return static_cast(a) / b; +} + +//// Arithmetic with int64_t + +inline C10_HOST_DEVICE BFloat16 operator+(BFloat16 a, int64_t b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator-(BFloat16 a, int64_t b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator*(BFloat16 a, int64_t b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE BFloat16 operator/(BFloat16 a, int64_t b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE BFloat16 operator+(int64_t a, BFloat16 b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE BFloat16 operator-(int64_t a, BFloat16 b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE BFloat16 operator*(int64_t a, BFloat16 b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE BFloat16 operator/(int64_t a, BFloat16 b) { + return static_cast(a) / b; +} + +// Overloading < and > operators, because std::max and std::min use them. + +inline C10_HOST_DEVICE bool operator>(BFloat16 &lhs, BFloat16 &rhs) { + return float(lhs) > float(rhs); +} + +inline C10_HOST_DEVICE bool operator<(BFloat16 &lhs, BFloat16 &rhs) { + return float(lhs) < float(rhs); +} + +} // namespace c10 + +namespace std { + +template <> class numeric_limits { +public: + static constexpr bool is_signed = true; + static constexpr bool is_specialized = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + static constexpr auto has_denorm = numeric_limits::has_denorm; + static constexpr auto has_denorm_loss = + numeric_limits::has_denorm_loss; + static constexpr auto round_style = numeric_limits::round_style; + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 8; + static constexpr int digits10 = 2; + static constexpr int max_digits10 = 4; + static constexpr int radix = 2; + static constexpr int min_exponent = -125; + static constexpr int min_exponent10 = -37; + static constexpr int max_exponent = 128; + static constexpr int max_exponent10 = 38; + static constexpr auto traps = numeric_limits::traps; + static constexpr auto tinyness_before = + numeric_limits::tinyness_before; + + static constexpr c10::BFloat16 min() { + return c10::BFloat16(0x0080, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 lowest() { + return c10::BFloat16(0xFF7F, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 max() { + return c10::BFloat16(0x7F7F, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 epsilon() { + return c10::BFloat16(0x3C00, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 round_error() { + return c10::BFloat16(0x3F00, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 infinity() { + return c10::BFloat16(0x7F80, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 quiet_NaN() { + return c10::BFloat16(0x7FC0, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 signaling_NaN() { + return c10::BFloat16(0x7F80, c10::BFloat16::from_bits()); + } + static constexpr c10::BFloat16 denorm_min() { + return c10::BFloat16(0x0001, c10::BFloat16::from_bits()); + } +}; + +} // namespace std + +C10_CLANG_DIAGNOSTIC_POP() diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-math.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-math.h new file mode 100644 index 0000000000..e5c7419261 --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-math.h @@ -0,0 +1,266 @@ +#pragma once + +#include +#include + +C10_CLANG_DIAGNOSTIC_PUSH() +#if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion") +#endif + +namespace c10 { +template +struct is_reduced_floating_point + : std::integral_constant || + std::is_same_v> {}; + +template +constexpr bool is_reduced_floating_point_v = + is_reduced_floating_point::value; +} // namespace c10 + +namespace std { + +#if !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED) +using c10::is_reduced_floating_point; +using c10::is_reduced_floating_point_v; +#endif // !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED) + +template , int> = 0> +inline T acos(T a) { + return std::acos(float(a)); +} +template , int> = 0> +inline T asin(T a) { + return std::asin(float(a)); +} +template , int> = 0> +inline T atan(T a) { + return std::atan(float(a)); +} +template , int> = 0> +inline T atanh(T a) { + return std::atanh(float(a)); +} +template , int> = 0> +inline T erf(T a) { + return std::erf(float(a)); +} +template , int> = 0> +inline T erfc(T a) { + return std::erfc(float(a)); +} +template , int> = 0> +inline T exp(T a) { + return std::exp(float(a)); +} +template , int> = 0> +inline T expm1(T a) { + return std::expm1(float(a)); +} +template , int> = 0> +inline bool isfinite(T a) { + return std::isfinite(float(a)); +} +template , int> = 0> +inline T log(T a) { + return std::log(float(a)); +} +template , int> = 0> +inline T log10(T a) { + return std::log10(float(a)); +} +template , int> = 0> +inline T log1p(T a) { + return std::log1p(float(a)); +} +template , int> = 0> +inline T log2(T a) { + return std::log2(float(a)); +} +template , int> = 0> +inline T ceil(T a) { + return std::ceil(float(a)); +} +template , int> = 0> +inline T cos(T a) { + return std::cos(float(a)); +} +template , int> = 0> +inline T floor(T a) { + return std::floor(float(a)); +} +template , int> = 0> +inline T nearbyint(T a) { + return std::nearbyint(float(a)); +} +template , int> = 0> +inline T sin(T a) { + return std::sin(float(a)); +} +template , int> = 0> +inline T tan(T a) { + return std::tan(float(a)); +} +template , int> = 0> +inline T sinh(T a) { + return std::sinh(float(a)); +} +template , int> = 0> +inline T cosh(T a) { + return std::cosh(float(a)); +} +template , int> = 0> +inline T tanh(T a) { + return std::tanh(float(a)); +} +template , int> = 0> +inline T trunc(T a) { + return std::trunc(float(a)); +} +template , int> = 0> +inline T lgamma(T a) { + return std::lgamma(float(a)); +} +template , int> = 0> +inline T sqrt(T a) { + return std::sqrt(float(a)); +} +template , int> = 0> +inline T rsqrt(T a) { + return 1.0 / std::sqrt(float(a)); +} +template , int> = 0> +inline T abs(T a) { + return std::abs(float(a)); +} +#if defined(_MSC_VER) && defined(__CUDACC__) +template , int> = 0> +inline T pow(T a, double b) { + return std::pow(float(a), float(b)); +} +#else +template , int> = 0> +inline T pow(T a, double b) { + return std::pow(float(a), b); +} +#endif +template , int> = 0> +inline T pow(T a, T b) { + return std::pow(float(a), float(b)); +} +template , int> = 0> +inline T fmod(T a, T b) { + return std::fmod(float(a), float(b)); +} + +/* + The following function is inspired from the implementation in `musl` + Link to License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT + ---------------------------------------------------------------------- + Copyright © 2005-2020 Rich Felker, et al. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ---------------------------------------------------------------------- + */ +template , int> = 0> +C10_HOST_DEVICE inline T nextafter(T from, T to) { + // Reference: + // https://git.musl-libc.org/cgit/musl/tree/src/math/nextafter.c + using int_repr_t = uint16_t; + constexpr uint8_t bits = 16; + union { + T f; + int_repr_t i; + } ufrom = {from}, uto = {to}; + + // get a mask to get the sign bit i.e. MSB + int_repr_t sign_mask = int_repr_t{1} << (bits - 1); + + // short-circuit: if either is NaN, return NaN + if (from != from || to != to) { + return from + to; + } + + // short-circuit: if they are exactly the same. + if (ufrom.i == uto.i) { + return from; + } + + // mask the sign-bit to zero i.e. positive + // equivalent to abs(x) + int_repr_t abs_from = ufrom.i & ~sign_mask; + int_repr_t abs_to = uto.i & ~sign_mask; + if (abs_from == 0) { + // if both are zero but with different sign, + // preserve the sign of `to`. + if (abs_to == 0) { + return to; + } + // smallest subnormal with sign of `to`. + ufrom.i = (uto.i & sign_mask) | int_repr_t{1}; + return ufrom.f; + } + + // if abs(from) > abs(to) or sign(from) != sign(to) + if (abs_from > abs_to || ((ufrom.i ^ uto.i) & sign_mask)) { + ufrom.i--; + } else { + ufrom.i++; + } + + return ufrom.f; +} + +} // namespace std + +C10_CLANG_DIAGNOSTIC_POP() diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16.h new file mode 100644 index 0000000000..e457e6dcc1 --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16.h @@ -0,0 +1,125 @@ +#pragma once + +// Defines the bloat16 type (brain floating-point). This representation uses +// 1 bit for the sign, 8 bits for the exponent and 7 bits for the mantissa. + +#include +#include +#include +#include +#include +#include + +#if defined(__CUDACC__) && !defined(USE_ROCM) +#include +#endif + +#if defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) +#if defined(CL_SYCL_LANGUAGE_VERSION) +#include // for SYCL 1.2.1 +#else +#include // for SYCL 2020 +#endif +#include +#endif + +namespace c10 { + +namespace detail { +inline C10_HOST_DEVICE float f32_from_bits(uint16_t src) { + float res = 0; + uint32_t tmp = src; + tmp <<= 16; + +#if defined(USE_ROCM) + float *tempRes; + + // We should be using memcpy in order to respect the strict aliasing rule + // but it fails in the HIP environment. + tempRes = reinterpret_cast(&tmp); + res = *tempRes; +#else + std::memcpy(&res, &tmp, sizeof(tmp)); +#endif + + return res; +} + +inline C10_HOST_DEVICE uint16_t bits_from_f32(float src) { + uint32_t res = 0; + +#if defined(USE_ROCM) + // We should be using memcpy in order to respect the strict aliasing rule + // but it fails in the HIP environment. + uint32_t *tempRes = reinterpret_cast(&src); + res = *tempRes; +#else + std::memcpy(&res, &src, sizeof(res)); +#endif + + return res >> 16; +} + +inline C10_HOST_DEVICE uint16_t round_to_nearest_even(float src) { +#if defined(USE_ROCM) + if (src != src) { +#elif defined(_MSC_VER) + if (isnan(src)) { +#else + if (std::isnan(src)) { +#endif + return UINT16_C(0x7FC0); + } else { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + union { + uint32_t U32; // NOLINT(facebook-hte-BadMemberName) + float F32; // NOLINT(facebook-hte-BadMemberName) + }; + + F32 = src; + uint32_t rounding_bias = ((U32 >> 16) & 1) + UINT32_C(0x7FFF); + return static_cast((U32 + rounding_bias) >> 16); + } +} +} // namespace detail + +struct alignas(2) BFloat16 { + uint16_t x; + + // HIP wants __host__ __device__ tag, CUDA does not +#if defined(USE_ROCM) + C10_HOST_DEVICE BFloat16() = default; +#else + BFloat16() = default; +#endif + + struct from_bits_t {}; + static constexpr C10_HOST_DEVICE from_bits_t from_bits() { + return from_bits_t(); + } + + constexpr C10_HOST_DEVICE BFloat16(unsigned short bits, from_bits_t) + : x(bits) {} + /* implicit */ inline C10_HOST_DEVICE BFloat16(float value); + inline C10_HOST_DEVICE operator float() const; + +#if defined(__CUDACC__) && !defined(USE_ROCM) + inline C10_HOST_DEVICE BFloat16(const __nv_bfloat16 &value); + explicit inline C10_HOST_DEVICE operator __nv_bfloat16() const; +#endif + +#if defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) + inline C10_HOST_DEVICE BFloat16(const sycl::ext::oneapi::bfloat16 &value); + explicit inline C10_HOST_DEVICE operator sycl::ext::oneapi::bfloat16() const; +#endif +}; + +C10_API inline std::ostream &operator<<(std::ostream &out, + const BFloat16 &value) { + out << (float)value; + return out; +} + +} // namespace c10 + +#include // IWYU pragma: keep diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/Half-inl.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/Half-inl.h new file mode 100644 index 0000000000..df2824bb69 --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/Half-inl.h @@ -0,0 +1,347 @@ +#pragma once + +#include +#include + +#include +#include + +#ifdef __CUDACC__ +#include +#endif + +#ifdef __HIPCC__ +#include +#endif + +#if defined(CL_SYCL_LANGUAGE_VERSION) +#include // for SYCL 1.2.1 +#elif defined(SYCL_LANGUAGE_VERSION) +#include // for SYCL 2020 +#endif + +#if (defined(CPU_CAPABILITY_AVX2) || defined(CPU_CAPABILITY_AVX512)) && \ + !defined(__APPLE__) +#include +#endif + +C10_CLANG_DIAGNOSTIC_PUSH() +#if C10_CLANG_HAS_WARNING("-Wimplicit-int-float-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") +#endif + +namespace c10 { + +#if defined(__aarch64__) && !defined(__CUDACC__) +/// Constructors +inline Half::Half(float16_t value) : x(detail::fp16_to_bits(value)) {} +inline Half::operator float16_t() const { return detail::fp16_from_bits(x); } +#else + +inline C10_HOST_DEVICE Half::Half(float value) + : +#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__) + x(__half_as_short(__float2half(value))) +#elif defined(__SYCL_DEVICE_ONLY__) + x(c10::bit_cast(sycl::half(value))) +#elif (defined(CPU_CAPABILITY_AVX2) || defined(CPU_CAPABILITY_AVX512)) && \ + !defined(__APPLE__) + x(at::vec::float2half_scalar(value)) +#else + x(detail::fp16_ieee_from_fp32_value(value)) +#endif +{ +} + +/// Implicit conversions + +inline C10_HOST_DEVICE Half::operator float() const { +#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__) + return __half2float(*reinterpret_cast(&x)); +#elif defined(__SYCL_DEVICE_ONLY__) + return float(c10::bit_cast(x)); +#elif (defined(CPU_CAPABILITY_AVX2) || defined(CPU_CAPABILITY_AVX512)) && \ + !defined(__APPLE__) + return at::vec::half2float_scalar(x); +#elif defined(__aarch64__) && !defined(__CUDACC__) + return detail::native_fp16_to_fp32_value(x); +#else + return detail::fp16_ieee_to_fp32_value(x); +#endif +} + +#endif /* !defined(__aarch64__) || defined(__CUDACC__) \ + */ + +#if defined(__CUDACC__) || defined(__HIPCC__) +inline C10_HOST_DEVICE Half::Half(const __half &value) { + x = *reinterpret_cast(&value); +} +inline C10_HOST_DEVICE Half::operator __half() const { + return *reinterpret_cast(&x); +} +#endif + +#ifdef SYCL_LANGUAGE_VERSION +inline C10_HOST_DEVICE Half::Half(const sycl::half &value) { + x = *reinterpret_cast(&value); +} +inline C10_HOST_DEVICE Half::operator sycl::half() const { + return *reinterpret_cast(&x); +} +#endif + +// CUDA intrinsics + +#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 350)) || \ + (defined(__clang__) && defined(__CUDA__)) +inline __device__ Half __ldg(const Half *ptr) { + return __ldg(reinterpret_cast(ptr)); +} +#endif + +/// Arithmetic + +inline C10_HOST_DEVICE Half operator+(const Half &a, const Half &b) { + return static_cast(a) + static_cast(b); +} + +inline C10_HOST_DEVICE Half operator-(const Half &a, const Half &b) { + return static_cast(a) - static_cast(b); +} + +inline C10_HOST_DEVICE Half operator*(const Half &a, const Half &b) { + return static_cast(a) * static_cast(b); +} + +inline C10_HOST_DEVICE Half operator/(const Half &a, const Half &b) + __ubsan_ignore_float_divide_by_zero__ { + return static_cast(a) / static_cast(b); +} + +inline C10_HOST_DEVICE Half operator-(const Half &a) { +#if (defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530) || \ + defined(__HIP_DEVICE_COMPILE__) + return __hneg(a); +#elif defined(__SYCL_DEVICE_ONLY__) + return -c10::bit_cast(a); +#else + return -static_cast(a); +#endif +} + +inline C10_HOST_DEVICE Half &operator+=(Half &a, const Half &b) { + a = a + b; + return a; +} + +inline C10_HOST_DEVICE Half &operator-=(Half &a, const Half &b) { + a = a - b; + return a; +} + +inline C10_HOST_DEVICE Half &operator*=(Half &a, const Half &b) { + a = a * b; + return a; +} + +inline C10_HOST_DEVICE Half &operator/=(Half &a, const Half &b) { + a = a / b; + return a; +} + +/// Arithmetic with floats + +inline C10_HOST_DEVICE float operator+(Half a, float b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE float operator-(Half a, float b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE float operator*(Half a, float b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE float +operator/(Half a, float b) __ubsan_ignore_float_divide_by_zero__ { + return static_cast(a) / b; +} + +inline C10_HOST_DEVICE float operator+(float a, Half b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE float operator-(float a, Half b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE float operator*(float a, Half b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE float +operator/(float a, Half b) __ubsan_ignore_float_divide_by_zero__ { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE float &operator+=(float &a, const Half &b) { + return a += static_cast(b); +} +inline C10_HOST_DEVICE float &operator-=(float &a, const Half &b) { + return a -= static_cast(b); +} +inline C10_HOST_DEVICE float &operator*=(float &a, const Half &b) { + return a *= static_cast(b); +} +inline C10_HOST_DEVICE float &operator/=(float &a, const Half &b) { + return a /= static_cast(b); +} + +/// Arithmetic with doubles + +inline C10_HOST_DEVICE double operator+(Half a, double b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE double operator-(Half a, double b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE double operator*(Half a, double b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE double +operator/(Half a, double b) __ubsan_ignore_float_divide_by_zero__ { + return static_cast(a) / b; +} + +inline C10_HOST_DEVICE double operator+(double a, Half b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE double operator-(double a, Half b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE double operator*(double a, Half b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE double +operator/(double a, Half b) __ubsan_ignore_float_divide_by_zero__ { + return a / static_cast(b); +} + +/// Arithmetic with ints + +inline C10_HOST_DEVICE Half operator+(Half a, int b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE Half operator-(Half a, int b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE Half operator*(Half a, int b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE Half operator/(Half a, int b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE Half operator+(int a, Half b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE Half operator-(int a, Half b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE Half operator*(int a, Half b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE Half operator/(int a, Half b) { + return static_cast(a) / b; +} + +//// Arithmetic with int64_t + +inline C10_HOST_DEVICE Half operator+(Half a, int64_t b) { + return a + static_cast(b); +} +inline C10_HOST_DEVICE Half operator-(Half a, int64_t b) { + return a - static_cast(b); +} +inline C10_HOST_DEVICE Half operator*(Half a, int64_t b) { + return a * static_cast(b); +} +inline C10_HOST_DEVICE Half operator/(Half a, int64_t b) { + return a / static_cast(b); +} + +inline C10_HOST_DEVICE Half operator+(int64_t a, Half b) { + return static_cast(a) + b; +} +inline C10_HOST_DEVICE Half operator-(int64_t a, Half b) { + return static_cast(a) - b; +} +inline C10_HOST_DEVICE Half operator*(int64_t a, Half b) { + return static_cast(a) * b; +} +inline C10_HOST_DEVICE Half operator/(int64_t a, Half b) { + return static_cast(a) / b; +} + +/// NOTE: we do not define comparisons directly and instead rely on the implicit +/// conversion from c10::Half to float. + +} // namespace c10 + +namespace std { + +template <> class numeric_limits { +public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + static constexpr auto has_denorm = numeric_limits::has_denorm; + static constexpr auto has_denorm_loss = + numeric_limits::has_denorm_loss; + static constexpr auto round_style = numeric_limits::round_style; + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 11; + static constexpr int digits10 = 3; + static constexpr int max_digits10 = 5; + static constexpr int radix = 2; + static constexpr int min_exponent = -13; + static constexpr int min_exponent10 = -4; + static constexpr int max_exponent = 16; + static constexpr int max_exponent10 = 4; + static constexpr auto traps = numeric_limits::traps; + static constexpr auto tinyness_before = + numeric_limits::tinyness_before; + static constexpr c10::Half min() { + return c10::Half(0x0400, c10::Half::from_bits()); + } + static constexpr c10::Half lowest() { + return c10::Half(0xFBFF, c10::Half::from_bits()); + } + static constexpr c10::Half max() { + return c10::Half(0x7BFF, c10::Half::from_bits()); + } + static constexpr c10::Half epsilon() { + return c10::Half(0x1400, c10::Half::from_bits()); + } + static constexpr c10::Half round_error() { + return c10::Half(0x3800, c10::Half::from_bits()); + } + static constexpr c10::Half infinity() { + return c10::Half(0x7C00, c10::Half::from_bits()); + } + static constexpr c10::Half quiet_NaN() { + return c10::Half(0x7E00, c10::Half::from_bits()); + } + static constexpr c10::Half signaling_NaN() { + return c10::Half(0x7D00, c10::Half::from_bits()); + } + static constexpr c10::Half denorm_min() { + return c10::Half(0x0001, c10::Half::from_bits()); + } +}; + +} // namespace std + +C10_CLANG_DIAGNOSTIC_POP() diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/Half.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/Half.h new file mode 100644 index 0000000000..8c32762c1a --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/Half.h @@ -0,0 +1,416 @@ +#pragma once + +/// Defines the Half type (half-precision floating-point) including conversions +/// to standard C types and basic arithmetic operations. Note that arithmetic +/// operations are implemented by converting to floating point and +/// performing the operation in float32, instead of using CUDA half intrinsics. +/// Most uses of this type within ATen are memory bound, including the +/// element-wise kernels, and the half intrinsics aren't efficient on all GPUs. +/// If you are writing a compute bound kernel, you can use the CUDA half +/// intrinsics directly on the Half type from device code. + +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +#include +#elif !defined(__OPENCL_VERSION__) +#include +#endif + +#ifdef _MSC_VER +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef __CUDACC__ +#include +#endif + +#ifdef __HIPCC__ +#include +#endif + +#if defined(CL_SYCL_LANGUAGE_VERSION) +#include // for SYCL 1.2.1 +#elif defined(SYCL_LANGUAGE_VERSION) +#include // for SYCL 2020 +#endif + +#if defined(__aarch64__) && !defined(__CUDACC__) +#include +#endif + +#if defined(__GNUC__) || defined(__clang__) +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \ + defined(_M_IX86) +#if defined(__F16C__) && !(defined(__CUDA_ARCH__) || defined(__CUDACC__) || \ + defined(__HIP_DEVICE_COMPILE__)) +#define C10_X86_F16 1 +#include // import conversion ops from f16cintrin.h +#endif // defined(__F16C__) && !(defined(__CUDA_ARCH__) || defined(__CUDACC__) + // || defined(__HIP_DEVICE_COMPILE__)) +#endif // __x86_64__ || _M_X64 || __i386 || _M_IX86 +#endif // __GNUC__ || __clang__ + +namespace c10 { + +namespace detail { + +/* + * Convert a 16-bit floating-point number in IEEE half-precision format, in bit + * representation, to a 32-bit floating-point number in IEEE single-precision + * format, in bit representation. + * + * @note The implementation doesn't use any floating-point operations. + */ +inline uint32_t fp16_ieee_to_fp32_bits(uint16_t h) { + /* + * Extend the half-precision floating-point number to 32 bits and shift to the + * upper part of the 32-bit word: + * +---+-----+------------+-------------------+ + * | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| + * +---+-----+------------+-------------------+ + * Bits 31 26-30 16-25 0-15 + * + * S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 + * - zero bits. + */ + const uint32_t w = (uint32_t)h << 16; + /* + * Extract the sign of the input number into the high bit of the 32-bit word: + * + * +---+----------------------------------+ + * | S |0000000 00000000 00000000 00000000| + * +---+----------------------------------+ + * Bits 31 0-31 + */ + const uint32_t sign = w & UINT32_C(0x80000000); + /* + * Extract mantissa and biased exponent of the input number into the bits 0-30 + * of the 32-bit word: + * + * +---+-----+------------+-------------------+ + * | 0 |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| + * +---+-----+------------+-------------------+ + * Bits 30 27-31 17-26 0-16 + */ + const uint32_t nonsign = w & UINT32_C(0x7FFFFFFF); + /* + * Renorm shift is the number of bits to shift mantissa left to make the + * half-precision number normalized. If the initial number is normalized, some + * of its high 6 bits (sign == 0 and 5-bit exponent) equals one. In this case + * renorm_shift == 0. If the number is denormalize, renorm_shift > 0. Note + * that if we shift denormalized nonsign by renorm_shift, the unit bit of + * mantissa will shift into exponent, turning the biased exponent into 1, and + * making mantissa normalized (i.e. without leading 1). + */ +#ifdef _MSC_VER + unsigned long nonsign_bsr; + _BitScanReverse(&nonsign_bsr, (unsigned long)nonsign); + uint32_t renorm_shift = (uint32_t)nonsign_bsr ^ 31; +#else + uint32_t renorm_shift = __builtin_clz(nonsign); +#endif + renorm_shift = renorm_shift > 5 ? renorm_shift - 5 : 0; + /* + * Iff half-precision number has exponent of 15, the addition overflows + * it into bit 31, and the subsequent shift turns the high 9 bits + * into 1. Thus inf_nan_mask == 0x7F800000 if the half-precision number + * had exponent of 15 (i.e. was NaN or infinity) 0x00000000 otherwise + */ + const int32_t inf_nan_mask = + ((int32_t)(nonsign + 0x04000000) >> 8) & INT32_C(0x7F800000); + /* + * Iff nonsign is 0, it overflows into 0xFFFFFFFF, turning bit 31 + * into 1. Otherwise, bit 31 remains 0. The signed shift right by 31 + * broadcasts bit 31 into all bits of the zero_mask. Thus zero_mask == + * 0xFFFFFFFF if the half-precision number was zero (+0.0h or -0.0h) + * 0x00000000 otherwise + */ + const int32_t zero_mask = (int32_t)(nonsign - 1) >> 31; + /* + * 1. Shift nonsign left by renorm_shift to normalize it (if the input + * was denormal) + * 2. Shift nonsign right by 3 so the exponent (5 bits originally) + * becomes an 8-bit field and 10-bit mantissa shifts into the 10 high + * bits of the 23-bit mantissa of IEEE single-precision number. + * 3. Add 0x70 to the exponent (starting at bit 23) to compensate the + * different in exponent bias (0x7F for single-precision number less 0xF + * for half-precision number). + * 4. Subtract renorm_shift from the exponent (starting at bit 23) to + * account for renormalization. As renorm_shift is less than 0x70, this + * can be combined with step 3. + * 5. Binary OR with inf_nan_mask to turn the exponent into 0xFF if the + * input was NaN or infinity. + * 6. Binary ANDNOT with zero_mask to turn the mantissa and exponent + * into zero if the input was zero. + * 7. Combine with the sign of the input number. + */ + return sign | + ((((nonsign << renorm_shift >> 3) + ((0x70 - renorm_shift) << 23)) | + inf_nan_mask) & + ~zero_mask); +} + +/* + * Convert a 16-bit floating-point number in IEEE half-precision format, in bit + * representation, to a 32-bit floating-point number in IEEE single-precision + * format. + * + * @note The implementation relies on IEEE-like (no assumption about rounding + * mode and no operations on denormals) floating-point operations and bitcasts + * between integer and floating-point variables. + */ +C10_HOST_DEVICE inline float fp16_ieee_to_fp32_value(uint16_t h) { +#ifdef C10_X86_F16 + return _cvtsh_ss(h); +#else + /* + * Extend the half-precision floating-point number to 32 bits and shift to the + * upper part of the 32-bit word: + * +---+-----+------------+-------------------+ + * | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| + * +---+-----+------------+-------------------+ + * Bits 31 26-30 16-25 0-15 + * + * S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 + * - zero bits. + */ + const uint32_t w = (uint32_t)h << 16; + /* + * Extract the sign of the input number into the high bit of the 32-bit word: + * + * +---+----------------------------------+ + * | S |0000000 00000000 00000000 00000000| + * +---+----------------------------------+ + * Bits 31 0-31 + */ + const uint32_t sign = w & UINT32_C(0x80000000); + /* + * Extract mantissa and biased exponent of the input number into the high bits + * of the 32-bit word: + * + * +-----+------------+---------------------+ + * |EEEEE|MM MMMM MMMM|0 0000 0000 0000 0000| + * +-----+------------+---------------------+ + * Bits 27-31 17-26 0-16 + */ + const uint32_t two_w = w + w; + + /* + * Shift mantissa and exponent into bits 23-28 and bits 13-22 so they become + * mantissa and exponent of a single-precision floating-point number: + * + * S|Exponent | Mantissa + * +-+---+-----+------------+----------------+ + * |0|000|EEEEE|MM MMMM MMMM|0 0000 0000 0000| + * +-+---+-----+------------+----------------+ + * Bits | 23-31 | 0-22 + * + * Next, there are some adjustments to the exponent: + * - The exponent needs to be corrected by the difference in exponent bias + * between single-precision and half-precision formats (0x7F - 0xF = 0x70) + * - Inf and NaN values in the inputs should become Inf and NaN values after + * conversion to the single-precision number. Therefore, if the biased + * exponent of the half-precision input was 0x1F (max possible value), the + * biased exponent of the single-precision output must be 0xFF (max possible + * value). We do this correction in two steps: + * - First, we adjust the exponent by (0xFF - 0x1F) = 0xE0 (see exp_offset + * below) rather than by 0x70 suggested by the difference in the exponent bias + * (see above). + * - Then we multiply the single-precision result of exponent adjustment by + * 2**(-112) to reverse the effect of exponent adjustment by 0xE0 less the + * necessary exponent adjustment by 0x70 due to difference in exponent bias. + * The floating-point multiplication hardware would ensure than Inf and + * NaN would retain their value on at least partially IEEE754-compliant + * implementations. + * + * Note that the above operations do not handle denormal inputs (where biased + * exponent == 0). However, they also do not operate on denormal inputs, and + * do not produce denormal results. + */ + constexpr uint32_t exp_offset = UINT32_C(0xE0) << 23; + // const float exp_scale = 0x1.0p-112f; + constexpr uint32_t scale_bits = (uint32_t)15 << 23; + float exp_scale_val = 0; + std::memcpy(&exp_scale_val, &scale_bits, sizeof(exp_scale_val)); + const float exp_scale = exp_scale_val; + const float normalized_value = + fp32_from_bits((two_w >> 4) + exp_offset) * exp_scale; + + /* + * Convert denormalized half-precision inputs into single-precision results + * (always normalized). Zero inputs are also handled here. + * + * In a denormalized number the biased exponent is zero, and mantissa has + * on-zero bits. First, we shift mantissa into bits 0-9 of the 32-bit word. + * + * zeros | mantissa + * +---------------------------+------------+ + * |0000 0000 0000 0000 0000 00|MM MMMM MMMM| + * +---------------------------+------------+ + * Bits 10-31 0-9 + * + * Now, remember that denormalized half-precision numbers are represented as: + * FP16 = mantissa * 2**(-24). + * The trick is to construct a normalized single-precision number with the + * same mantissa and thehalf-precision input and with an exponent which would + * scale the corresponding mantissa bits to 2**(-24). A normalized + * single-precision floating-point number is represented as: FP32 = (1 + + * mantissa * 2**(-23)) * 2**(exponent - 127) Therefore, when the biased + * exponent is 126, a unit change in the mantissa of the input denormalized + * half-precision number causes a change of the constructed single-precision + * number by 2**(-24), i.e. the same amount. + * + * The last step is to adjust the bias of the constructed single-precision + * number. When the input half-precision number is zero, the constructed + * single-precision number has the value of FP32 = 1 * 2**(126 - 127) = + * 2**(-1) = 0.5 Therefore, we need to subtract 0.5 from the constructed + * single-precision number to get the numerical equivalent of the input + * half-precision number. + */ + constexpr uint32_t magic_mask = UINT32_C(126) << 23; + constexpr float magic_bias = 0.5f; + const float denormalized_value = + fp32_from_bits((two_w >> 17) | magic_mask) - magic_bias; + + /* + * - Choose either results of conversion of input as a normalized number, or + * as a denormalized number, depending on the input exponent. The variable + * two_w contains input exponent in bits 27-31, therefore if its smaller than + * 2**27, the input is either a denormal number, or zero. + * - Combine the result of conversion of exponent and mantissa with the sign + * of the input number. + */ + constexpr uint32_t denormalized_cutoff = UINT32_C(1) << 27; + const uint32_t result = + sign | (two_w < denormalized_cutoff ? fp32_to_bits(denormalized_value) + : fp32_to_bits(normalized_value)); + return fp32_from_bits(result); +#endif // C10_X86_F16 +} + +/* + * Convert a 32-bit floating-point number in IEEE single-precision format to a + * 16-bit floating-point number in IEEE half-precision format, in bit + * representation. + * + * @note The implementation relies on IEEE-like (no assumption about rounding + * mode and no operations on denormals) floating-point operations and bitcasts + * between integer and floating-point variables. + */ +inline uint16_t fp16_ieee_from_fp32_value(float f) { +#ifdef C10_X86_F16 + return _cvtss_sh(f, _MM_FROUND_TO_NEAREST_INT); +#else + // const float scale_to_inf = 0x1.0p+112f; + // const float scale_to_zero = 0x1.0p-110f; + constexpr uint32_t scale_to_inf_bits = (uint32_t)239 << 23; + constexpr uint32_t scale_to_zero_bits = (uint32_t)17 << 23; + float scale_to_inf_val = 0, scale_to_zero_val = 0; + std::memcpy(&scale_to_inf_val, &scale_to_inf_bits, sizeof(scale_to_inf_val)); + std::memcpy(&scale_to_zero_val, &scale_to_zero_bits, + sizeof(scale_to_zero_val)); + const float scale_to_inf = scale_to_inf_val; + const float scale_to_zero = scale_to_zero_val; + +#if defined(_MSC_VER) && _MSC_VER == 1916 + float base = ((signbit(f) != 0 ? -f : f) * scale_to_inf) * scale_to_zero; +#else + float base = (fabsf(f) * scale_to_inf) * scale_to_zero; +#endif + + const uint32_t w = fp32_to_bits(f); + const uint32_t shl1_w = w + w; + const uint32_t sign = w & UINT32_C(0x80000000); + uint32_t bias = shl1_w & UINT32_C(0xFF000000); + if (bias < UINT32_C(0x71000000)) { + bias = UINT32_C(0x71000000); + } + + base = fp32_from_bits((bias >> 1) + UINT32_C(0x07800000)) + base; + const uint32_t bits = fp32_to_bits(base); + const uint32_t exp_bits = (bits >> 13) & UINT32_C(0x00007C00); + const uint32_t mantissa_bits = bits & UINT32_C(0x00000FFF); + const uint32_t nonsign = exp_bits + mantissa_bits; + return static_cast( + (sign >> 16) | + (shl1_w > UINT32_C(0xFF000000) ? UINT16_C(0x7E00) : nonsign)); +#endif // C10_X86_F16 +} + +#ifdef C10_X86_F16 +#undef C10_X86_F16 +#endif // C10_X86_F16 + +#if defined(__aarch64__) && !defined(__CUDACC__) +inline float16_t fp16_from_bits(uint16_t h) { + return c10::bit_cast(h); +} + +inline uint16_t fp16_to_bits(float16_t f) { return c10::bit_cast(f); } + +// According to https://godbolt.org/z/frExdbsWG it would translate to single +// fcvt s0, h0 +inline float native_fp16_to_fp32_value(uint16_t h) { + return static_cast(fp16_from_bits(h)); +} + +inline uint16_t native_fp16_from_fp32_value(float f) { + return fp16_to_bits(static_cast(f)); +} +#endif + +} // namespace detail + +struct alignas(2) Half { + unsigned short x; + + struct from_bits_t {}; + C10_HOST_DEVICE static constexpr from_bits_t from_bits() { + return from_bits_t(); + } + + // HIP wants __host__ __device__ tag, CUDA does not +#if defined(USE_ROCM) + C10_HOST_DEVICE Half() = default; +#else + Half() = default; +#endif + + constexpr C10_HOST_DEVICE Half(unsigned short bits, from_bits_t) : x(bits) {} +#if defined(__aarch64__) && !defined(__CUDACC__) + inline Half(float16_t value); + inline operator float16_t() const; +#else + inline C10_HOST_DEVICE Half(float value); + inline C10_HOST_DEVICE operator float() const; +#endif + +#if defined(__CUDACC__) || defined(__HIPCC__) + inline C10_HOST_DEVICE Half(const __half &value); + inline C10_HOST_DEVICE operator __half() const; +#endif +#ifdef SYCL_LANGUAGE_VERSION + inline C10_HOST_DEVICE Half(const sycl::half &value); + inline C10_HOST_DEVICE operator sycl::half() const; +#endif +}; + +C10_API inline std::ostream &operator<<(std::ostream &out, const Half &value) { + out << (float)value; + return out; +} + +} // namespace c10 + +#include // IWYU pragma: keep diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h new file mode 100644 index 0000000000..3ec70e6b69 --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h @@ -0,0 +1,133 @@ +#pragma once + +#include +#include +#include + +C10_CLANG_DIAGNOSTIC_PUSH() +#if C10_CLANG_HAS_WARNING("-Wstring-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wstring-conversion") +#endif +#if C10_CLANG_HAS_WARNING("-Wimplicit-int-float-conversion") +C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") +#endif + +namespace c10 { + +/// Returns false since we cannot have x < 0 if x is unsigned. +template +inline constexpr bool is_negative(const T & /*x*/, + std::true_type /*is_unsigned*/) { + return false; +} + +/// Returns true if a signed variable x < 0 +template +inline constexpr bool is_negative(const T &x, std::false_type /*is_unsigned*/) { + return x < T(0); +} + +/// Returns true if x < 0 +/// NOTE: Will fail on an unsigned custom type +/// For the most part it's possible to fix this if +/// the custom type has a constexpr constructor. +/// However, notably, c10::Half does not :-( +template inline constexpr bool is_negative(const T &x) { + return is_negative(x, std::is_unsigned()); +} + +/// Returns the sign of an unsigned variable x as 0, 1 +template +inline constexpr int signum(const T &x, std::true_type /*is_unsigned*/) { + return T(0) < x; +} + +/// Returns the sign of a signed variable x as -1, 0, 1 +template +inline constexpr int signum(const T &x, std::false_type /*is_unsigned*/) { + return (T(0) < x) - (x < T(0)); +} + +/// Returns the sign of x as -1, 0, 1 +/// NOTE: Will fail on an unsigned custom type +/// For the most part it's possible to fix this if +/// the custom type has a constexpr constructor. +/// However, notably, c10::Half does not :-( +template inline constexpr int signum(const T &x) { + return signum(x, std::is_unsigned()); +} + +/// Returns true if a and b are not both negative +template +inline constexpr bool signs_differ(const T &a, const U &b) { + return is_negative(a) != is_negative(b); +} + +// Suppress sign compare warning when compiling with GCC +// as later does not account for short-circuit rule before +// raising the warning, see https://godbolt.org/z/Tr3Msnz99 +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#endif + +/// Returns true if x is greater than the greatest value of the type Limit +template +inline constexpr bool greater_than_max(const T &x) { + constexpr bool can_overflow = + std::numeric_limits::digits > std::numeric_limits::digits; + return can_overflow && x > std::numeric_limits::max(); +} + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +/// Returns true if x < lowest(Limit). Standard comparison +template +inline constexpr bool less_than_lowest(const T &x, + std::false_type /*limit_is_unsigned*/, + std::false_type /*x_is_unsigned*/) { + return x < std::numeric_limits::lowest(); +} + +/// Returns false since all the limit is signed and therefore includes +/// negative values but x cannot be negative because it is unsigned +template +inline constexpr bool less_than_lowest(const T & /*x*/, + std::false_type /*limit_is_unsigned*/, + std::true_type /*x_is_unsigned*/) { + return false; +} + +/// Returns true if x < 0, where 0 is constructed from T. +/// Limit is not signed, so its lower value is zero +template +inline constexpr bool less_than_lowest(const T &x, + std::true_type /*limit_is_unsigned*/, + std::false_type /*x_is_unsigned*/) { + return x < T(0); +} + +/// Returns false sign both types are unsigned +template +inline constexpr bool less_than_lowest(const T & /*x*/, + std::true_type /*limit_is_unsigned*/, + std::true_type /*x_is_unsigned*/) { + return false; +} + +/// Returns true if x is less than the lowest value of type T +/// NOTE: Will fail on an unsigned custom type +/// For the most part it's possible to fix this if +/// the custom type has a constexpr constructor. +/// However, notably, c10::Half does not : +template +inline constexpr bool less_than_lowest(const T &x) { + return less_than_lowest(x, std::is_unsigned(), + std::is_unsigned()); +} + +} // namespace c10 + +C10_CLANG_DIAGNOSTIC_POP() diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/bit_cast.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/bit_cast.h new file mode 100644 index 0000000000..640c9c0294 --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/bit_cast.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#if __has_include() && (__cplusplus >= 202002L || (defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L)) +#include +#define C10_HAVE_STD_BIT_CAST 1 +#else +#define C10_HAVE_STD_BIT_CAST 0 +#endif // __has_include() && (__cplusplus >= 202002L || + // (defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L)) + +namespace c10 { + +#if C10_HAVE_STD_BIT_CAST +using std::bit_cast; +#else +// Implementations of std::bit_cast() from C++ 20. +// +// This is a less sketchy version of reinterpret_cast. +// +// See https://en.cppreference.com/w/cpp/numeric/bit_cast for more +// information as well as the source of our implementations. +template +std::enable_if_t && + std::is_trivially_copyable_v, + To> +// constexpr support needs compiler magic +bit_cast(const From &src) noexcept { + static_assert(std::is_trivially_constructible_v, + "This implementation additionally requires " + "destination type to be trivially constructible"); + + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; +} +#endif // C10_HAVE_STD_BIT_CAST +#undef C10_HAVE_STD_BIT_CAST + +} // namespace c10 diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/floating_point_utils.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/floating_point_utils.h new file mode 100644 index 0000000000..b240c4ea23 --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/floating_point_utils.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +namespace c10::detail { + +C10_HOST_DEVICE inline float fp32_from_bits(uint32_t w) { +#if defined(__OPENCL_VERSION__) + return as_float(w); +#elif defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__) + return __uint_as_float((unsigned int)w); +#elif defined(__INTEL_COMPILER) + return _castu32_f32(w); +#else + return c10::bit_cast(w); +#endif +} + +C10_HOST_DEVICE inline uint32_t fp32_to_bits(float f) { +#if defined(__OPENCL_VERSION__) + return as_uint(f); +#elif defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__) + return (uint32_t)__float_as_uint(f); +#elif defined(__INTEL_COMPILER) + return _castf32_u32(f); +#else + return c10::bit_cast(f); +#endif +} + +} // namespace c10::detail diff --git a/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/irange.h b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/irange.h new file mode 100644 index 0000000000..72a748cb0e --- /dev/null +++ b/third-party/include/executorch/runtime/core/portable_type/c10/c10/util/irange.h @@ -0,0 +1,107 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include +#include + +namespace c10 { + +namespace detail { + +template , int> = 0> +struct integer_iterator { + using iterator_category = std::input_iterator_tag; + using value_type = I; + using difference_type = std::ptrdiff_t; + using pointer = I *; + using reference = I &; + + explicit constexpr integer_iterator(I value_) : value(value_) {} + + constexpr I operator*() const { return value; } + + constexpr I const *operator->() const { return &value; } + + constexpr integer_iterator &operator++() { + ++value; + return *this; + } + + constexpr integer_iterator operator++(int) { + const auto copy = *this; + ++*this; + return copy; + } + + constexpr bool operator==(const integer_iterator &other) const { + if constexpr (one_sided) { + // Range-for loops' end test is `begin != end`, not `begin < + // end`. To handle `c10::irange(n)` where n < 0 (which should be + // empty), we just make `begin != end` fail whenever `end` is + // negative. + return is_negative(other.value) || value == other.value; + } else { + return value == other.value; + } + // Suppress "warning: missing return statement at end of non-void function" + // which Nvidia's Robert Crovella confirms is an NVCC compiler error + // here https://stackoverflow.com/a/64561686/752843 on 2020-10-27 + // `__builtin_unreachable();` would be best here, but it's not + // available with all compilers. So we instead return an arbitrary + // value trusting that this line will, in fact, never be reached. + return false; // Horrible hack + } + + constexpr bool operator!=(const integer_iterator &other) const { + return !(*this == other); + } + +protected: + I value; +}; + +} // namespace detail + +template , bool> = true> +struct integer_range { +public: + constexpr integer_range(I begin, I end) : begin_(begin), end_(end) {} + using iterator = detail::integer_iterator; + constexpr iterator begin() const { return begin_; } + constexpr iterator end() const { return end_; } + +private: + iterator begin_; + iterator end_; +}; + +/// Creates an integer range for the half-open interval [begin, end) +/// If end<=begin, then the range is empty. +/// The range has the type of the `end` integer; `begin` integer is +/// cast to this type. +template , bool> = true, + std::enable_if_t, bool> = true> +integer_range irange(Integer1 begin, Integer2 end) { + // If end<=begin then the range is empty; we can achieve this effect by + // choosing the larger of {begin, end} as the loop terminator + return {static_cast(begin), + std::max(static_cast(begin), end)}; +} + +/// Creates an integer range for the half-open interval [0, end) +/// If end<=begin, then the range is empty +template , bool> = true> +constexpr integer_range irange(Integer end) { + return {Integer(), end}; +} + +} // namespace c10 diff --git a/third-party/include/executorch/runtime/core/portable_type/half.h b/third-party/include/executorch/runtime/core/portable_type/half.h index fd48fabec4..bf4c676ce8 100644 --- a/third-party/include/executorch/runtime/core/portable_type/half.h +++ b/third-party/include/executorch/runtime/core/portable_type/half.h @@ -8,645 +8,20 @@ #pragma once -#include -#include -#include -#include -#include - -#if defined(__GNUC__) || defined(__clang__) -#if defined(__aarch64__) -#ifndef __ARM_V8_ONLY__ -#define NATIVE_FP16 1 -#endif // __ARM_V8_ONLY__ -#endif // __aarch64__ -#endif // GNUC or clang - -#if defined(__GNUC__) || defined(__clang__) -#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \ - defined(_M_IX86) -#if defined(__AVX2__) -#define X86_F16 1 -#include // import conversion ops from f16cintrin.h -#endif // __AVX2__ -#endif // __x86_64__ || _M_X64 || __i386 || _M_IX86 -#endif // __GNUC__ || __clang__ - -namespace executorch { -namespace runtime { -namespace etensor { - -/** - * A half-precision floating point type, compatible with c10/util/Half.h from - * pytorch core. - */ -struct alignas(2) Half { - union { -#ifdef NATIVE_FP16 - _Float16 y; -#endif - uint16_t x; - }; - - struct from_bits_t {}; - static constexpr from_bits_t from_bits() { return from_bits_t(); } - - Half() = default; - - constexpr Half(uint16_t bits, from_bits_t) : x(bits) {} - /* implicit */ inline Half(float value); - inline operator float() const; -}; +#include +namespace executorch::runtime::etensor { +using c10::Half; namespace internal { - -inline float fp32_from_bits(uint32_t w) { - static_assert(sizeof(float) == sizeof(uint32_t)); - union { - uint32_t as_bits; - float as_value; - } fp32 = {w}; - return fp32.as_value; -} - -inline uint32_t fp32_to_bits(float f) { - static_assert(sizeof(float) == sizeof(uint32_t)); - union { - float as_value; - uint32_t as_bits; - } fp32 = {f}; - return fp32.as_bits; -} - -/* - * Convert a 16-bit floating-point number in IEEE half-precision format, in bit - * representation, to a 32-bit floating-point number in IEEE single-precision - * format, in bit representation. - * - * @note The implementation doesn't use any floating-point operations. - */ -inline uint32_t fp16_ieee_to_fp32_bits(uint16_t h) { - /* - * Extend the half-precision floating-point number to 32 bits and shift to the - * upper part of the 32-bit word: - * +---+-----+------------+-------------------+ - * | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| - * +---+-----+------------+-------------------+ - * Bits 31 26-30 16-25 0-15 - * - * S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 - * - zero bits. - */ - const uint32_t w = (uint32_t)h << 16; - /* - * Extract the sign of the input number into the high bit of the 32-bit word: - * - * +---+----------------------------------+ - * | S |0000000 00000000 00000000 00000000| - * +---+----------------------------------+ - * Bits 31 0-31 - */ - const uint32_t sign = w & UINT32_C(0x80000000); - /* - * Extract mantissa and biased exponent of the input number into the bits 0-30 - * of the 32-bit word: - * - * +---+-----+------------+-------------------+ - * | 0 |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| - * +---+-----+------------+-------------------+ - * Bits 30 27-31 17-26 0-16 - */ - const uint32_t nonsign = w & UINT32_C(0x7FFFFFFF); - /* - * Renorm shift is the number of bits to shift mantissa left to make the - * half-precision number normalized. If the initial number is normalized, some - * of its high 6 bits (sign == 0 and 5-bit exponent) equals one. In this case - * renorm_shift == 0. If the number is denormalize, renorm_shift > 0. Note - * that if we shift denormalized nonsign by renorm_shift, the unit bit of - * mantissa will shift into exponent, turning the biased exponent into 1, and - * making mantissa normalized (i.e. without leading 1). - */ -#ifdef _MSC_VER - unsigned long nonsign_bsr; - _BitScanReverse(&nonsign_bsr, (unsigned long)nonsign); - uint32_t renorm_shift = (uint32_t)nonsign_bsr ^ 31; -#else - uint32_t renorm_shift = __builtin_clz(nonsign); -#endif - renorm_shift = renorm_shift > 5 ? renorm_shift - 5 : 0; - /* - * Iff half-precision number has exponent of 15, the addition overflows - * it into bit 31, and the subsequent shift turns the high 9 bits - * into 1. Thus inf_nan_mask == 0x7F800000 if the half-precision number - * had exponent of 15 (i.e. was NaN or infinity) 0x00000000 otherwise - */ - const int32_t inf_nan_mask = - ((int32_t)(nonsign + 0x04000000) >> 8) & INT32_C(0x7F800000); - /* - * Iff nonsign is 0, it overflows into 0xFFFFFFFF, turning bit 31 - * into 1. Otherwise, bit 31 remains 0. The signed shift right by 31 - * broadcasts bit 31 into all bits of the zero_mask. Thus zero_mask == - * 0xFFFFFFFF if the half-precision number was zero (+0.0h or -0.0h) - * 0x00000000 otherwise - */ - const int32_t zero_mask = (int32_t)(nonsign - 1) >> 31; - /* - * 1. Shift nonsign left by renorm_shift to normalize it (if the input - * was denormal) - * 2. Shift nonsign right by 3 so the exponent (5 bits originally) - * becomes an 8-bit field and 10-bit mantissa shifts into the 10 high - * bits of the 23-bit mantissa of IEEE single-precision number. - * 3. Add 0x70 to the exponent (starting at bit 23) to compensate the - * different in exponent bias (0x7F for single-precision number less 0xF - * for half-precision number). - * 4. Subtract renorm_shift from the exponent (starting at bit 23) to - * account for renormalization. As renorm_shift is less than 0x70, this - * can be combined with step 3. - * 5. Binary OR with inf_nan_mask to turn the exponent into 0xFF if the - * input was NaN or infinity. - * 6. Binary ANDNOT with zero_mask to turn the mantissa and exponent - * into zero if the input was zero. - * 7. Combine with the sign of the input number. - */ - return sign | - ((((nonsign << renorm_shift >> 3) + ((0x70 - renorm_shift) << 23)) | - inf_nan_mask) & - ~zero_mask); -} - -/* - * Convert a 16-bit floating-point number in IEEE half-precision format, in bit - * representation, to a 32-bit floating-point number in IEEE single-precision - * format. - * - * @note The implementation relies on IEEE-like (no assumption about rounding - * mode and no operations on denormals) floating-point operations and bitcasts - * between integer and floating-point variables. - */ -inline float fp16_ieee_to_fp32_value(uint16_t h) { -#ifdef X86_F16 - return _cvtsh_ss(h); -#else - - /* - * Extend the half-precision floating-point number to 32 bits and shift to the - * upper part of the 32-bit word: - * +---+-----+------------+-------------------+ - * | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000| - * +---+-----+------------+-------------------+ - * Bits 31 26-30 16-25 0-15 - * - * S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 - * - zero bits. - */ - const uint32_t w = (uint32_t)h << 16; - /* - * Extract the sign of the input number into the high bit of the 32-bit word: - * - * +---+----------------------------------+ - * | S |0000000 00000000 00000000 00000000| - * +---+----------------------------------+ - * Bits 31 0-31 - */ - const uint32_t sign = w & UINT32_C(0x80000000); - /* - * Extract mantissa and biased exponent of the input number into the high bits - * of the 32-bit word: - * - * +-----+------------+---------------------+ - * |EEEEE|MM MMMM MMMM|0 0000 0000 0000 0000| - * +-----+------------+---------------------+ - * Bits 27-31 17-26 0-16 - */ - const uint32_t two_w = w + w; - - /* - * Shift mantissa and exponent into bits 23-28 and bits 13-22 so they become - * mantissa and exponent of a single-precision floating-point number: - * - * S|Exponent | Mantissa - * +-+---+-----+------------+----------------+ - * |0|000|EEEEE|MM MMMM MMMM|0 0000 0000 0000| - * +-+---+-----+------------+----------------+ - * Bits | 23-31 | 0-22 - * - * Next, there are some adjustments to the exponent: - * - The exponent needs to be corrected by the difference in exponent bias - * between single-precision and half-precision formats (0x7F - 0xF = 0x70) - * - Inf and NaN values in the inputs should become Inf and NaN values after - * conversion to the single-precision number. Therefore, if the biased - * exponent of the half-precision input was 0x1F (max possible value), the - * biased exponent of the single-precision output must be 0xFF (max possible - * value). We do this correction in two steps: - * - First, we adjust the exponent by (0xFF - 0x1F) = 0xE0 (see exp_offset - * below) rather than by 0x70 suggested by the difference in the exponent bias - * (see above). - * - Then we multiply the single-precision result of exponent adjustment by - * 2**(-112) to reverse the effect of exponent adjustment by 0xE0 less the - * necessary exponent adjustment by 0x70 due to difference in exponent bias. - * The floating-point multiplication hardware would ensure than Inf and - * NaN would retain their value on at least partially IEEE754-compliant - * implementations. - * - * Note that the above operations do not handle denormal inputs (where biased - * exponent == 0). However, they also do not operate on denormal inputs, and - * do not produce denormal results. - */ - constexpr uint32_t exp_offset = UINT32_C(0xE0) << 23; - // const float exp_scale = 0x1.0p-112f; - constexpr uint32_t scale_bits = (uint32_t)15 << 23; - float exp_scale_val = 0; - std::memcpy(&exp_scale_val, &scale_bits, sizeof(exp_scale_val)); - const float exp_scale = exp_scale_val; - const float normalized_value = - fp32_from_bits((two_w >> 4) + exp_offset) * exp_scale; - - /* - * Convert denormalized half-precision inputs into single-precision results - * (always normalized). Zero inputs are also handled here. - * - * In a denormalized number the biased exponent is zero, and mantissa has - * on-zero bits. First, we shift mantissa into bits 0-9 of the 32-bit word. - * - * zeros | mantissa - * +---------------------------+------------+ - * |0000 0000 0000 0000 0000 00|MM MMMM MMMM| - * +---------------------------+------------+ - * Bits 10-31 0-9 - * - * Now, remember that denormalized half-precision numbers are represented as: - * FP16 = mantissa * 2**(-24). - * The trick is to construct a normalized single-precision number with the - * same mantissa and thehalf-precision input and with an exponent which would - * scale the corresponding mantissa bits to 2**(-24). A normalized - * single-precision floating-point number is represented as: FP32 = (1 + - * mantissa * 2**(-23)) * 2**(exponent - 127) Therefore, when the biased - * exponent is 126, a unit change in the mantissa of the input denormalized - * half-precision number causes a change of the constructed single-precision - * number by 2**(-24), i.e. the same amount. - * - * The last step is to adjust the bias of the constructed single-precision - * number. When the input half-precision number is zero, the constructed - * single-precision number has the value of FP32 = 1 * 2**(126 - 127) = - * 2**(-1) = 0.5 Therefore, we need to subtract 0.5 from the constructed - * single-precision number to get the numerical equivalent of the input - * half-precision number. - */ - constexpr uint32_t magic_mask = UINT32_C(126) << 23; - constexpr float magic_bias = 0.5f; - const float denormalized_value = - fp32_from_bits((two_w >> 17) | magic_mask) - magic_bias; - - /* - * - Choose either results of conversion of input as a normalized number, or - * as a denormalized number, depending on the input exponent. The variable - * two_w contains input exponent in bits 27-31, therefore if its smaller than - * 2**27, the input is either a denormal number, or zero. - * - Combine the result of conversion of exponent and mantissa with the sign - * of the input number. - */ - constexpr uint32_t denormalized_cutoff = UINT32_C(1) << 27; - const uint32_t result = - sign | (two_w < denormalized_cutoff ? fp32_to_bits(denormalized_value) - : fp32_to_bits(normalized_value)); - return fp32_from_bits(result); - -#endif // not X86_F16 -} - -/* - * Convert a 32-bit floating-point number in IEEE single-precision format to a - * 16-bit floating-point number in IEEE half-precision format, in bit - * representation. - * - * @note The implementation relies on IEEE-like (no assumption about rounding - * mode and no operations on denormals) floating-point operations and bitcasts - * between integer and floating-point variables. - */ -inline uint16_t fp16_ieee_from_fp32_value(float f) { -#ifdef X86_F16 - return _cvtss_sh(f, _MM_FROUND_TO_NEAREST_INT); -#else - - // const float scale_to_inf = 0x1.0p+112f; - // const float scale_to_zero = 0x1.0p-110f; - constexpr uint32_t scale_to_inf_bits = (uint32_t)239 << 23; - constexpr uint32_t scale_to_zero_bits = (uint32_t)17 << 23; - float scale_to_inf_val = 0, scale_to_zero_val = 0; - std::memcpy(&scale_to_inf_val, &scale_to_inf_bits, sizeof(scale_to_inf_val)); - std::memcpy(&scale_to_zero_val, &scale_to_zero_bits, - sizeof(scale_to_zero_val)); - const float scale_to_inf = scale_to_inf_val; - const float scale_to_zero = scale_to_zero_val; - -#if defined(_MSC_VER) && _MSC_VER == 1916 - float base = ((signbit(f) != 0 ? -f : f) * scale_to_inf) * scale_to_zero; -#else - float base = (fabsf(f) * scale_to_inf) * scale_to_zero; -#endif - - const uint32_t w = fp32_to_bits(f); - const uint32_t shl1_w = w + w; - const uint32_t sign = w & UINT32_C(0x80000000); - uint32_t bias = shl1_w & UINT32_C(0xFF000000); - if (bias < UINT32_C(0x71000000)) { - bias = UINT32_C(0x71000000); - } - - base = fp32_from_bits((bias >> 1) + UINT32_C(0x07800000)) + base; - const uint32_t bits = fp32_to_bits(base); - const uint32_t exp_bits = (bits >> 13) & UINT32_C(0x00007C00); - const uint32_t mantissa_bits = bits & UINT32_C(0x00000FFF); - const uint32_t nonsign = exp_bits + mantissa_bits; - return static_cast( - (sign >> 16) | - (shl1_w > UINT32_C(0xFF000000) ? UINT16_C(0x7E00) : nonsign)); -#endif // not X86_F16 -} - +using c10::detail::fp16_ieee_from_fp32_value; +using c10::detail::fp16_ieee_to_fp32_bits; +using c10::detail::fp16_ieee_to_fp32_value; +using c10::detail::fp32_from_bits; +using c10::detail::fp32_to_bits; } // namespace internal - -/// Constructors -#ifdef NATIVE_FP16 -inline Half::Half(float value) : y(value) {} -#else -inline Half::Half(float value) - : x(internal::fp16_ieee_from_fp32_value(value)) {} -#endif - -/// Implicit conversions -#ifdef NATIVE_FP16 -inline Half::operator float() const { return (float)y; } -#else -inline Half::operator float() const { - return internal::fp16_ieee_to_fp32_value(x); -} -#endif - -/// Arithmetic - -#ifdef NATIVE_FP16 - -#define return_half(r) \ - do { \ - Half ret; \ - ret.y = r; \ - return ret; \ - } while (0) - -inline Half operator+(const Half &a, const Half &b) { return_half(a.y + b.y); } - -inline Half operator-(const Half &a, const Half &b) { - return_half(a.y - b.y); - return static_cast(a) - static_cast(b); -} - -inline Half operator*(const Half &a, const Half &b) { return_half(a.y * b.y); } - -inline Half operator/(const Half &a, const Half &b) { return_half(a.y / b.y); } - -inline Half operator-(const Half &a) { return_half(-a.y); } - -inline Half &operator+=(Half &a, const Half &b) { - a.y += b.y; - return a; -} - -inline Half &operator-=(Half &a, const Half &b) { - a.y -= b.y; - return a; -} - -inline Half &operator*=(Half &a, const Half &b) { - a.y *= b.y; - return a; -} - -inline Half &operator/=(Half &a, const Half &b) { - a.y /= b.y; - return a; -} - -#else - -inline Half operator+(const Half &a, const Half &b) { - return static_cast(a) + static_cast(b); -} - -inline Half operator-(const Half &a, const Half &b) { - return static_cast(a) - static_cast(b); -} - -inline Half operator*(const Half &a, const Half &b) { - return static_cast(a) * static_cast(b); -} - -inline Half operator/(const Half &a, const Half &b) { - return static_cast(a) / static_cast(b); -} - -inline Half operator-(const Half &a) { return -static_cast(a); } - -inline Half &operator+=(Half &a, const Half &b) { - a = a + b; - return a; -} - -inline Half &operator-=(Half &a, const Half &b) { - a = a - b; - return a; -} - -inline Half &operator*=(Half &a, const Half &b) { - a = a * b; - return a; -} - -inline Half &operator/=(Half &a, const Half &b) { - a = a / b; - return a; -} - -#endif - -/// Arithmetic with floats - -inline float operator+(Half a, float b) { return static_cast(a) + b; } -inline float operator-(Half a, float b) { return static_cast(a) - b; } -inline float operator*(Half a, float b) { return static_cast(a) * b; } -inline float operator/(Half a, float b) { return static_cast(a) / b; } - -inline float operator+(float a, Half b) { return a + static_cast(b); } -inline float operator-(float a, Half b) { return a - static_cast(b); } -inline float operator*(float a, Half b) { return a * static_cast(b); } -inline float operator/(float a, Half b) { return a / static_cast(b); } - -inline float &operator+=(float &a, const Half &b) { - return a += static_cast(b); -} -inline float &operator-=(float &a, const Half &b) { - return a -= static_cast(b); -} -inline float &operator*=(float &a, const Half &b) { - return a *= static_cast(b); -} -inline float &operator/=(float &a, const Half &b) { - return a /= static_cast(b); -} - -/// Arithmetic with doubles - -inline double operator+(Half a, double b) { return static_cast(a) + b; } -inline double operator-(Half a, double b) { return static_cast(a) - b; } -inline double operator*(Half a, double b) { return static_cast(a) * b; } -inline double operator/(Half a, double b) { return static_cast(a) / b; } - -inline double operator+(double a, Half b) { return a + static_cast(b); } -inline double operator-(double a, Half b) { return a - static_cast(b); } -inline double operator*(double a, Half b) { return a * static_cast(b); } -inline double operator/(double a, Half b) { return a / static_cast(b); } - -/// Arithmetic with ints - -#ifdef NATIVE_FP16 - -inline Half operator+(Half a, int32_t b) { return_half(a.y + b); } -inline Half operator-(Half a, int32_t b) { return_half(a.y - b); } -inline Half operator*(Half a, int32_t b) { return_half(a.y * b); } -inline Half operator/(Half a, int32_t b) { return_half(a.y / b); } - -inline Half operator+(int32_t a, Half b) { return_half(a + b.y); } -inline Half operator-(int32_t a, Half b) { return_half(a - b.y); } -inline Half operator*(int32_t a, Half b) { return_half(a * b.y); } -inline Half operator/(int32_t a, Half b) { return_half(a / b.y); } - -#else - -inline Half operator+(Half a, int32_t b) { return a + static_cast(b); } -inline Half operator-(Half a, int32_t b) { return a - static_cast(b); } -inline Half operator*(Half a, int32_t b) { return a * static_cast(b); } -inline Half operator/(Half a, int32_t b) { return a / static_cast(b); } - -inline Half operator+(int32_t a, Half b) { return static_cast(a) + b; } -inline Half operator-(int32_t a, Half b) { return static_cast(a) - b; } -inline Half operator*(int32_t a, Half b) { return static_cast(a) * b; } -inline Half operator/(int32_t a, Half b) { return static_cast(a) / b; } - -#endif - -//// Arithmetic with int64_t - -#ifdef NATIVE_FP16 - -inline Half operator+(Half a, int64_t b) { return_half(a.y + b); } -inline Half operator-(Half a, int64_t b) { return_half(a.y - b); } -inline Half operator*(Half a, int64_t b) { return_half(a.y * b); } -inline Half operator/(Half a, int64_t b) { return_half(a.y / b); } - -inline Half operator+(int64_t a, Half b) { return_half(a + b.y); } -inline Half operator-(int64_t a, Half b) { return_half(a - b.y); } -inline Half operator*(int64_t a, Half b) { return_half(a * b.y); } -inline Half operator/(int64_t a, Half b) { return_half(a / b.y); } - -#else - -inline Half operator+(Half a, int64_t b) { return a + static_cast(b); } -inline Half operator-(Half a, int64_t b) { return a - static_cast(b); } -inline Half operator*(Half a, int64_t b) { return a * static_cast(b); } -inline Half operator/(Half a, int64_t b) { return a / static_cast(b); } - -inline Half operator+(int64_t a, Half b) { return static_cast(a) + b; } -inline Half operator-(int64_t a, Half b) { return static_cast(a) - b; } -inline Half operator*(int64_t a, Half b) { return static_cast(a) * b; } -inline Half operator/(int64_t a, Half b) { return static_cast(a) / b; } - -#endif - -/// NOTE: we do not define comparisons directly and instead rely on the implicit -/// conversion Half to float. - -static inline std::ostream & -operator<<(std::ostream &out, const executorch::runtime::etensor::Half &value) { - out << (float)value; - return out; -} - -} // namespace etensor -} // namespace runtime -} // namespace executorch -namespace torch { -namespace executor { +} // namespace executorch::runtime::etensor +namespace torch::executor { // TODO(T197294990): Remove these deprecated aliases once all users have moved // to the new `::executorch` namespaces. using ::executorch::runtime::etensor::Half; -} // namespace executor -} // namespace torch - -namespace std { - -template <> class numeric_limits { -public: - static constexpr bool is_specialized = true; - static constexpr bool is_signed = true; - static constexpr bool is_integer = false; - static constexpr bool is_exact = false; - static constexpr bool has_infinity = true; - static constexpr bool has_quiet_NaN = true; - static constexpr bool has_signaling_NaN = true; - static constexpr auto has_denorm = numeric_limits::has_denorm; - static constexpr auto has_denorm_loss = - numeric_limits::has_denorm_loss; - static constexpr auto round_style = numeric_limits::round_style; - static constexpr bool is_iec559 = true; - static constexpr bool is_bounded = true; - static constexpr bool is_modulo = false; - static constexpr int digits = 11; - static constexpr int digits10 = 3; - static constexpr int max_digits10 = 5; - static constexpr int radix = 2; - static constexpr int min_exponent = -13; - static constexpr int min_exponent10 = -4; - static constexpr int max_exponent = 16; - static constexpr int max_exponent10 = 4; - static constexpr auto traps = numeric_limits::traps; - static constexpr auto tinyness_before = - numeric_limits::tinyness_before; - static constexpr executorch::runtime::etensor::Half min() { - return executorch::runtime::etensor::Half( - 0x0400, executorch::runtime::etensor::Half::from_bits()); - } - static constexpr executorch::runtime::etensor::Half lowest() { - return executorch::runtime::etensor::Half( - 0xFBFF, executorch::runtime::etensor::Half::from_bits()); - } - static constexpr executorch::runtime::etensor::Half max() { - return executorch::runtime::etensor::Half( - 0x7BFF, executorch::runtime::etensor::Half::from_bits()); - } - static constexpr executorch::runtime::etensor::Half epsilon() { - return executorch::runtime::etensor::Half( - 0x1400, executorch::runtime::etensor::Half::from_bits()); - } - static constexpr executorch::runtime::etensor::Half round_error() { - return executorch::runtime::etensor::Half( - 0x3800, executorch::runtime::etensor::Half::from_bits()); - } - static constexpr executorch::runtime::etensor::Half infinity() { - return executorch::runtime::etensor::Half( - 0x7C00, executorch::runtime::etensor::Half::from_bits()); - } - static constexpr executorch::runtime::etensor::Half quiet_NaN() { - return executorch::runtime::etensor::Half( - 0x7E00, executorch::runtime::etensor::Half::from_bits()); - } - static constexpr executorch::runtime::etensor::Half signaling_NaN() { - return executorch::runtime::etensor::Half( - 0x7D00, executorch::runtime::etensor::Half::from_bits()); - } - static constexpr executorch::runtime::etensor::Half denorm_min() { - return executorch::runtime::etensor::Half( - 0x0001, executorch::runtime::etensor::Half::from_bits()); - } -}; - -} // namespace std +} // namespace torch::executor diff --git a/third-party/include/executorch/runtime/core/portable_type/optional.h b/third-party/include/executorch/runtime/core/portable_type/optional.h index f9df468193..31ad06fd09 100644 --- a/third-party/include/executorch/runtime/core/portable_type/optional.h +++ b/third-party/include/executorch/runtime/core/portable_type/optional.h @@ -8,162 +8,18 @@ #pragma once -#include -#include -#include // std::forward and other template magic checks +#include namespace executorch { namespace runtime { namespace etensor { -/// Used to indicate an optional type with uninitialized state. -struct nullopt_t final { - constexpr explicit nullopt_t(int32_t) {} -}; - -/// A constant of type nullopt_t that is used to indicate an optional type with -/// uninitialized state. -constexpr nullopt_t nullopt{0}; - -/// Leaner optional class, subset of c10, std, and boost optional APIs. -template class optional final { -public: - /// The type wrapped by the optional class. - using value_type = T; - - /// Constructs an optional object that does not contain a value. - /* implicit */ optional() noexcept : storage_(trivial_init), init_(false) {} - - /// Constructs an optional object that does not contain a value. - /* implicit */ optional(nullopt_t) noexcept - : storage_(trivial_init), init_(false) {} - - /// Constructs an optional object that matches the state of v. - /* implicit */ optional(const optional &v) - : storage_(trivial_init), init_(v.init_) { - if (init_) { - new (&storage_.value_) T(v.storage_.value_); - } - } - - /// Constructs an optional object that contains the specified value. - /* implicit */ optional(const T &v) : storage_(v), init_(true) {} - - /// Constructs an optional object from v. - /* implicit */ optional(optional &&v) noexcept( - std::is_nothrow_move_constructible::value) - : storage_(trivial_init), init_(v.init_) { - if (init_) { - new (&storage_.value_) T(std::forward(v.storage_.value_)); - } - } - - /// Constructs an optional object that contains the specified value. - /* implicit */ optional(T &&v) : storage_(std::forward(v)), init_(true) {} - - optional &operator=(const optional &rhs) { - if (init_ && !rhs.init_) { - clear(); - } else if (!init_ && rhs.init_) { - init_ = true; - new (&storage_.value_) T(rhs.storage_.value_); - } else if (init_ && rhs.init_) { - storage_.value_ = rhs.storage_.value_; - } - return *this; - } - - optional &operator=(optional &&rhs) noexcept( - std::is_nothrow_move_assignable::value && - std::is_nothrow_move_constructible::value) { - if (init_ && !rhs.init_) { - clear(); - } else if (!init_ && rhs.init_) { - init_ = true; - new (&storage_.value_) T(std::forward(rhs.storage_.value_)); - } else if (init_ && rhs.init_) { - storage_.value_ = std::forward(rhs.storage_.value_); - } - return *this; - } - - /// Destroys the stored value if there is one - ~optional() { - if (init_) { - storage_.value_.~T(); - } - } - - optional &operator=(nullopt_t) noexcept { - clear(); - return *this; - } - - /// Returns true if the object contains a value, false otherwise - explicit operator bool() const noexcept { return init_; } - - /// Returns true if the object contains a value, false otherwise - bool has_value() const noexcept { return init_; } - - /// Returns a constant reference to the contained value. Calls ET_CHECK if - /// the object does not contain a value. - T const &value() const & { - ET_CHECK(init_); - return contained_val(); - } - - /// Returns a mutable reference to the contained value. Calls ET_CHECK if the - /// object does not contain a value. - T &value() & { - ET_CHECK(init_); - return contained_val(); - } - - /// Returns an rvalue of the contained value. Calls ET_CHECK if the object - /// does not contain a value. - T &&value() && { - ET_CHECK(init_); - return std::forward(contained_val()); - } - -private: - // Used to invoke the dummy ctor of storage_t in the initializer lists of - // optional_base as default ctor is implicitly deleted because T is nontrivial - struct trivial_init_t { - } trivial_init{}; - - /** - * A wrapper type that lets us avoid constructing a T when there is no value. - * If there is a value present, the optional class must destroy it. - */ - union storage_t { - /// A small, trivially-constructable alternative to T. - unsigned char dummy_; - /// The constructed value itself, if optional::has_value_ is true. - T value_; - - /* implicit */ storage_t(trivial_init_t) { dummy_ = 0; } - - template - storage_t(Args &&...args) : value_(std::forward(args)...) {} - - ~storage_t() {} - }; - - const T &contained_val() const & { return storage_.value_; } - T &&contained_val() && { return std::move(storage_.value_); } - T &contained_val() & { return storage_.value_; } - - void clear() noexcept { - if (init_) { - storage_.value_.~T(); - } - init_ = false; - } - - storage_t storage_; - bool init_; -}; +// NOLINTNEXTLINE(misc-unused-using-decls) +using std::nullopt; +// NOLINTNEXTLINE(misc-unused-using-decls) +using std::nullopt_t; +// NOLINTNEXTLINE(misc-unused-using-decls) +using std::optional; } // namespace etensor } // namespace runtime diff --git a/third-party/include/executorch/runtime/core/result.h b/third-party/include/executorch/runtime/core/result.h index 00cc7bb8db..bd9ce433a3 100644 --- a/third-party/include/executorch/runtime/core/result.h +++ b/third-party/include/executorch/runtime/core/result.h @@ -59,6 +59,10 @@ template class Result final { */ /* implicit */ Result(Error error) : error_(error == Error::Ok ? Error::Internal : error), hasValue_(false) { + if ET_UNLIKELY (error == Error::Ok) { + ET_LOG(Debug, "Attempted to create Result from Error::Ok, this has been " + "converted to Error::Internal."); + } } /// Value copy constructor. diff --git a/third-party/include/executorch/runtime/core/span.h b/third-party/include/executorch/runtime/core/span.h index 903a6d271e..7e0a6b3461 100644 --- a/third-party/include/executorch/runtime/core/span.h +++ b/third-party/include/executorch/runtime/core/span.h @@ -34,6 +34,7 @@ namespace runtime { */ template class Span final { public: + using value_type = T; using iterator = T *; using size_type = size_t; diff --git a/third-party/include/executorch/runtime/core/tag.h b/third-party/include/executorch/runtime/core/tag.h index 8c32910532..32e6093750 100644 --- a/third-party/include/executorch/runtime/core/tag.h +++ b/third-party/include/executorch/runtime/core/tag.h @@ -9,6 +9,8 @@ #pragma once #include +#include +#include namespace executorch { namespace runtime { @@ -36,6 +38,27 @@ enum class Tag : uint32_t { #undef DEFINE_TAG }; +/** + * Convert a tag value to a string representation. If ET_ENABLE_ENUM_STRINGS is + * set (it is on by default), this will return a string name (for example, + * "Tensor"). Otherwise, it will return a string representation of the index + * value ("1"). + * + * If the user buffer is not large enough to hold the string representation, the + * string will be truncated. + * + * The return value is the number of characters written, or in the case of + * truncation, the number of characters that would be written if the buffer was + * large enough. + */ +size_t tag_to_string(Tag tag, char *buffer, size_t buffer_size); + +/* The size of the buffer needed to hold the longest tag string, including the + * null terminator. This value is expected to be updated manually, but it + * checked in test_tag.cpp. + */ +constexpr size_t kTagNameBufferSize = 19; + } // namespace runtime } // namespace executorch diff --git a/third-party/include/executorch/runtime/core/tensor_layout.h b/third-party/include/executorch/runtime/core/tensor_layout.h new file mode 100644 index 0000000000..42e8bdb58c --- /dev/null +++ b/third-party/include/executorch/runtime/core/tensor_layout.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include + +namespace executorch { +namespace runtime { + +/** + * Describes the layout of a tensor. + */ +class ET_EXPERIMENTAL TensorLayout final { +public: + TensorLayout() = delete; + + /** + * Creates a TensorLayout from the given parameters. + * + * @param[in] sizes The sizes of the tensor. Note: the span passed here must + * outlive the TensorLayout and all copies of it. + * @param[in] dim_order The dim order of the tensor. Note: the span passed + * here must outlive the TensorLayout and all copies of it. + * @param[in] scalar_type The scalar type of the tensor. + * @return A Result containing the TensorLayout on success, or an error. + */ + static executorch::runtime::Result + create(Span sizes, Span dim_order, + executorch::aten::ScalarType scalar_type); + + /** + * Returns the sizes of the tensor. + * + * NOTE: The TensorLayout must outlive the spans returned here. + */ + Span sizes() const { return sizes_; } + + /** + * Returns the dim order of the tensor. + * + * NOTE: The TensorLayout must outlive the spans returned here. + */ + Span dim_order() const { return dim_order_; } + + /// Returns the scalar type of the tensor. + executorch::aten::ScalarType scalar_type() const { return scalar_type_; } + + /// Returns the size of the tensor in bytes. + size_t nbytes() const { return nbytes_; } + +private: + TensorLayout(Span sizes, Span dim_order, + executorch::aten::ScalarType scalar_type, size_t nbytes) + : sizes_(sizes), dim_order_(dim_order), scalar_type_(scalar_type), + nbytes_(nbytes) {} + /// The sizes of the tensor. + const Span sizes_; + + /// The dim order of the tensor. + const Span dim_order_; + + /// The scalar type of the tensor. + const executorch::aten::ScalarType scalar_type_; + + /// The size in bytes of the tensor. + const size_t nbytes_; +}; + +} // namespace runtime +} // namespace executorch diff --git a/third-party/include/executorch/runtime/executor/method.h b/third-party/include/executorch/runtime/executor/method.h index 06aaf5a8ed..3f574e4754 100644 --- a/third-party/include/executorch/runtime/executor/method.h +++ b/third-party/include/executorch/runtime/executor/method.h @@ -8,9 +8,16 @@ #pragma once +#ifdef __GNUC__ +// Disable -Wdeprecated-declarations, as some builds use 'Werror'. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + #include #include #include +#include #include #include #include @@ -27,6 +34,12 @@ struct EValue; namespace executorch { namespace runtime { +// Forward declare NamedData. This is a public header and must not include +// internal data types. +namespace deserialization { +struct NamedData; +} // namespace deserialization + // Forward declare Program to avoid a circular reference. class Program; @@ -38,6 +51,7 @@ using OpFunction = void (*)(KernelRuntimeContext &, EValue **); /// A list of pointers into the master values table that together compose the /// argument list for a single instruction using InstructionArgs = Span; +using deserialization::NamedData; /** * An executable method of an executorch program. Maps to a python method like @@ -57,13 +71,17 @@ class Method final { event_tracer_(rhs.event_tracer_), n_value_(rhs.n_value_), values_(rhs.values_), n_delegate_(rhs.n_delegate_), delegates_(rhs.delegates_), n_chains_(rhs.n_chains_), - chains_(rhs.chains_), init_state_(rhs.init_state_) { + chains_(rhs.chains_), external_constants_(rhs.external_constants_), + n_external_constants_(rhs.n_external_constants_), + init_state_(rhs.init_state_) { // Required: clear out fields that the dtor looks at, so that we don't free // anything twice. rhs.n_value_ = 0; rhs.values_ = nullptr; rhs.n_delegate_ = 0; rhs.delegates_ = nullptr; + rhs.n_external_constants_ = 0; + rhs.external_constants_ = nullptr; // Helpful: Try to ensure that any other interactions with the old object // result in failures. @@ -268,19 +286,22 @@ class Method final { temp_allocator_(temp_allocator), serialization_plan_(nullptr), event_tracer_(event_tracer), n_value_(0), values_(nullptr), n_delegate_(0), delegates_(nullptr), n_chains_(0), chains_(nullptr), + external_constants_(nullptr), n_external_constants_(0), init_state_(InitializationState::Uninitialized) {} /// Static factory used by Program. ET_NODISCARD static Result load(executorch_flatbuffer::ExecutionPlan *s_plan, const Program *program, - MemoryManager *memory_manager, EventTracer *event_tracer); + MemoryManager *memory_manager, EventTracer *event_tracer, + const NamedDataMap *named_data_map); /** * Initialize the method from its serialized representation. * * @returns Error::Ok on success, non-Ok on failure. */ - ET_NODISCARD Error init(executorch_flatbuffer::ExecutionPlan *s_plan); + ET_NODISCARD Error init(executorch_flatbuffer::ExecutionPlan *s_plan, + const NamedDataMap *named_data_map); /// Returns true if the Method was successfully initialized. inline bool initialized() const { @@ -311,14 +332,37 @@ class Method final { size_t n_chains_; Chain *chains_; + NamedData *external_constants_; + size_t n_external_constants_ = 0; + InitializationState init_state_; + /** + * Counts the number of tensors marked as EXTERNAL in the flatbuffer + * for this method. + */ + ET_NODISCARD Result get_num_external_constants(); + + /** + * Parses the flatbuffer for constant tensors tagged as EXTERNAL. + * Retrieves the external constants using the named_data_map and places them + * into `external_constants_`. Updates `n_external_constants_` to count the + * number of successfully-initialized external constants. + * FreeableBuffers returned by the named_data_map are owned by the + * method and are freed on method destruction. + * + * @param[in] named_data_map, to retrieve external constants from. + * @returns Error::Ok on success, non-Ok on failure. + */ + ET_NODISCARD Error + parse_external_constants(const NamedDataMap *named_data_map); + /** * Parses the elements of the values_ array. On error, n_value_ will be set to * the number of successfully-initialized entries so that ~Method doesn't try * to clean up uninitialized entries. */ - ET_NODISCARD Error parse_values(); + ET_NODISCARD Error parse_values(const NamedDataMap *named_data_map); ET_NODISCARD Error resolve_operator(int32_t op_index, OpFunction *kernels, size_t kernel_index, InstructionArgs args, @@ -337,3 +381,7 @@ namespace executor { using ::executorch::runtime::Method; } // namespace executor } // namespace torch + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/third-party/include/executorch/runtime/executor/method_meta.h b/third-party/include/executorch/runtime/executor/method_meta.h index 7675ea2ef7..f4a0c101e2 100644 --- a/third-party/include/executorch/runtime/executor/method_meta.h +++ b/third-party/include/executorch/runtime/executor/method_meta.h @@ -183,6 +183,30 @@ class MethodMeta final { */ Result memory_planned_buffer_size(size_t index) const; + /** + * Check to see if a backend is used in this method. + * + * @param[in] backend_name The name of the backend to search for. + * @returns true if a backend is used in this method, otherwise false. + */ + bool uses_backend(const char *backend_name) const; + + /** + * Get the number of backends used in this method. + * + * @returns The total number of backend names. + */ + size_t num_backends() const; + + /** + * Get the backend name at the given index. + * + * @param[in] index The index of the backend name. + * @returns A Result wrapping the backend name as a C-style string + * on success, or an error if the index is invalid. + */ + Result get_backend_name(size_t index) const; + /** * Get the number of instructions in this method. * diff --git a/third-party/include/executorch/runtime/executor/program.h b/third-party/include/executorch/runtime/executor/program.h index 3c4e30ef2d..9e1a447c17 100644 --- a/third-party/include/executorch/runtime/executor/program.h +++ b/third-party/include/executorch/runtime/executor/program.h @@ -8,8 +8,15 @@ #pragma once +#ifdef __GNUC__ +// Disable -Wdeprecated-declarations, as some builds use 'Werror'. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + #include #include +#include #include #include @@ -19,6 +26,7 @@ #include #include #include +#include #include // Forward declare flatbuffer types. This is a public header and must not @@ -100,6 +108,12 @@ class Program final { Result get_constant_buffer_data(size_t buffer_idx, size_t nbytes) const; + /** + * Get the named data map from the program. + * @return The named data map. + */ + Result get_named_data_map() const; + /** * Returns the number of methods in the program. */ @@ -124,12 +138,15 @@ class Program final { * execution of the loaded method. If `memory_manager.temp_allocator()` is * null, the runtime will allocate temp memory using `et_pal_allocate()`. * @param[in] event_tracer The event tracer to use for this method run. + * @param[in] named_data_map An optional map of {name, blob} used to resolve + * data that is external to the PTE, if any. * * @returns The loaded method on success, or an error on failure. */ - Result load_method(const char *method_name, - MemoryManager *memory_manager, - EventTracer *event_tracer = nullptr) const; + Result + load_method(const char *method_name, MemoryManager *memory_manager, + EventTracer *event_tracer = nullptr, + const NamedDataMap *named_data_map = nullptr) const; /** * Gathers metadata for the named method. @@ -251,13 +268,15 @@ class Program final { Program(DataLoader *loader, size_t segment_base_offset, FreeableBuffer &&program_data, const executorch_flatbuffer::Program *internal_program, - FreeableBuffer &&constant_segment_data) + FreeableBuffer &&constant_segment_data, + std::optional &&pte_data_map) : program_data_(std::move(program_data)), // Don't need the loader if there are no segments. loader_(segment_base_offset > 0 ? loader : nullptr), internal_program_(internal_program), segment_base_offset_(segment_base_offset), - constant_segment_data_(std::move(constant_segment_data)) {} + constant_segment_data_(std::move(constant_segment_data)), + pte_data_map_(std::move(pte_data_map)) {} // Not copyable or assignable. Program(const Program &rhs) = delete; @@ -280,6 +299,9 @@ class Program final { /// Constant segment data. FreeableBuffer constant_segment_data_; + + /// NamedDataMap holding named data from the program. + std::optional pte_data_map_; }; } // namespace runtime @@ -292,3 +314,7 @@ namespace executor { using ::executorch::runtime::Program; } // namespace executor } // namespace torch + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/third-party/include/executorch/runtime/executor/pte_data_map.h b/third-party/include/executorch/runtime/executor/pte_data_map.h new file mode 100644 index 0000000000..63fb65bca8 --- /dev/null +++ b/third-party/include/executorch/runtime/executor/pte_data_map.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +// Forward declare flatbuffer types. This is a public header and must not +// include the generated flatbuffer header. +namespace executorch_flatbuffer { +struct NamedData; +struct DataSegment; +} // namespace executorch_flatbuffer + +namespace flatbuffers { +template struct Offset; +} // namespace flatbuffers + +// @lint-ignore CLANGTIDY facebook-modularize-issue-check +#if EXECUTORCH_INTERNAL_FLATBUFFERS == 1 +// TODO(T216992074): update internal flatbuffers (v1.12) to match OSS (v24.3.5). +namespace flatbuffers { +template class Vector; +using FlatbufferNamedData = + flatbuffers::Vector>; +using FlatbufferDataSegment = flatbuffers::Vector< + flatbuffers::Offset>; +} // namespace flatbuffers +#else +namespace flatbuffers { +template class Vector; +using FlatbufferNamedData = + flatbuffers::Vector, + uint32_t>; +using FlatbufferDataSegment = + flatbuffers::Vector, + uint32_t>; +} // namespace flatbuffers +#endif + +namespace executorch { +namespace runtime { +namespace internal { + +/** + * A NamedDataMap implementation for Flatbuffer-serialized named data + * originating from a PTE file. + */ +class PteDataMap final : public NamedDataMap { +public: + /** + * Creates a new DataMap that wraps named_data from the PTE file. + * + * @param[in] loader The DataLoader that accesses the PTE file. + * Note: the loader must outlive the PteDataMap instance. + * @param[in] segment_base_offset The offset to the first segment in the PTE + * file, in bytes. + * @param[in] named_data The named_data from the PTE file. Note: the pointer + * passed here must outlive the PteDataMap instance. + * @param[in] segments The segments from the PTE file. Note: the pointer + * passed here must outlive the PteDataMap instance. + */ + static Result + create(DataLoader *loader, size_t segment_base_offset, + const flatbuffers::FlatbufferNamedData *named_data, + const flatbuffers::FlatbufferDataSegment *segments); + + /** + * The PteDataMap currently only handles opaque data that does not contain + * tensor-specific metadata. + */ + ET_NODISCARD + Result + get_metadata(ET_UNUSED const char *key) const override { + return Error::NotImplemented; + } + + /** + * Retrieve read-only data for the specified key. + * + * @param[in] key The name of the blob to get data on. + * + * @return error if the key is not present or data cannot be loaded. + */ + ET_NODISCARD + Result get_data(const char *key) const override; + + /** + * The PteDataMap currently does not implement load_into. + */ + ET_NODISCARD Error load_data_into(ET_UNUSED const char *key, + ET_UNUSED void *buffer, + ET_UNUSED size_t size) const override { + return Error::NotImplemented; + } + + /** + * @returns The number of keys in the map. + */ + ET_NODISCARD Result get_num_keys() const override; + + /** + * @returns The key at the specified index, error if index out of bounds. + */ + ET_NODISCARD Result get_key(size_t index) const override; + + // Moveable, to be compatible with Result. + PteDataMap(PteDataMap &&) noexcept = default; + ~PteDataMap() override = default; + +private: + PteDataMap(DataLoader *loader, size_t segment_base_offset, + const flatbuffers::FlatbufferNamedData *named_data, + const flatbuffers::FlatbufferDataSegment *segments) + : loader_(loader), segment_base_offset_(segment_base_offset), + named_data_(named_data), segments_(segments) {} + + // Not copyable or assignable. + PteDataMap(const PteDataMap &rhs) = delete; + PteDataMap &operator=(PteDataMap &&rhs) noexcept = delete; + PteDataMap &operator=(const PteDataMap &rhs) = delete; + + // Data loader, used to load segment data. + DataLoader *loader_; + + // The offset to the first segment in the PTE file, in bytes. + size_t segment_base_offset_; + + // Named data, containing name and segment index. + const flatbuffers::FlatbufferNamedData *named_data_; + + // Segments, to retrieve offset and size for the loader. + const flatbuffers::FlatbufferDataSegment *segments_; +}; + +} // namespace internal +} // namespace runtime +} // namespace executorch diff --git a/third-party/include/executorch/runtime/executor/tensor_parser.h b/third-party/include/executorch/runtime/executor/tensor_parser.h index a256109cac..1d0df38d6e 100644 --- a/third-party/include/executorch/runtime/executor/tensor_parser.h +++ b/third-party/include/executorch/runtime/executor/tensor_parser.h @@ -8,6 +8,12 @@ #pragma once +#ifdef __GNUC__ +// Disable -Wdeprecated-declarations, as some builds use 'Werror'. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + #include #include #include @@ -18,13 +24,31 @@ namespace executorch { namespace runtime { namespace deserialization { +/// Data structure to hold key and data buffer for external data used +/// in a method. +struct NamedData { + const char *key; + FreeableBuffer buffer; +}; + +NamedData *get_data_by_key(const char *key, Span entries); + ET_NODISCARD Result parseTensor(const Program *program, MemoryManager *memory_manager, - const executorch_flatbuffer::Tensor *s_tensor); + const executorch_flatbuffer::Tensor *s_tensor, + const NamedDataMap *named_data_map = nullptr, + Span external_constants = {}); ET_NODISCARD Result> parseTensorList(const flatbuffers::Vector *tensor_indices, - EValue *values_, MemoryManager *memory_manager); + EValue *values, size_t values_len, + MemoryManager *memory_manager); + +// Checks that the sizes, dim_order and scalar_type match between tensors +// stored in the PTE and externally. +ET_NODISCARD Error +validateTensorLayout(const executorch_flatbuffer::Tensor *s_tensor, + const TensorLayout &expected_layout); // Deserializes a List of optional type. The code here is the same between all // list of optionals: list of optional Tensor, list of optional float etc, so we @@ -32,7 +56,8 @@ parseTensorList(const flatbuffers::Vector *tensor_indices, template ET_NODISCARD Result>> parseListOptionalType(const flatbuffers::Vector *value_indices, - EValue *values_, MemoryManager *memory_manager) { + EValue *values, size_t values_len, + MemoryManager *memory_manager) { auto *evalp_list = memory_manager->method_allocator()->allocateList( value_indices->size()); if (evalp_list == nullptr) { @@ -51,7 +76,7 @@ parseListOptionalType(const flatbuffers::Vector *value_indices, // already allocated) and stick it in the list. for (int32_t index : *value_indices) { // Lists of objects are stored in fbb as list[int] where the ints are - // indices into values_. Currently serialization is deciding if they want to + // indices into values. Currently serialization is deciding if they want to // put -1 for serialized None type indices, or give us a valid index to a // serialized None. We support either for now. // Placement new as the list elements are not initialized, so calling @@ -64,9 +89,12 @@ parseListOptionalType(const flatbuffers::Vector *value_indices, // TODO(T161156879): do something less hacky here. evalp_list[output_idx] = nullptr; } else { + ET_CHECK_OR_RETURN_ERROR( + index >= 0 && static_cast(index) < values_len, InvalidProgram, + "Invalid value index %" PRId32 " for ListOptional", index); new (&optional_tensor_list[output_idx]) - executorch::aten::optional(values_[index].toOptional()); - evalp_list[output_idx] = &values_[static_cast(index)]; + executorch::aten::optional(values[index].toOptional()); + evalp_list[output_idx] = &values[static_cast(index)]; } output_idx++; } @@ -89,6 +117,12 @@ parseListOptionalType(const flatbuffers::Vector *value_indices, * @param[in] program The Program to use for constant buffer data. * @param[in] nbytes The amount of memory to get from the allocator. * @param[in] allocator The source of memory for non-constant tensors. + * @param[in] named_data_map An optional map of {name, blob} used to resolve + * data that is mutable and external to the PTE, if any. + * @param[in] external_constants An optional span containing tensor fqn to + * corresponding tensor data. Used to resolve data that is constant and + * external to the PTE, if any. Referencing data from external_constants is + * safe, as it has the same lifetime as the method. * * @returns On success, the data pointer to use for the tensor. On failure, a * non-Ok Error. @@ -96,7 +130,9 @@ parseListOptionalType(const flatbuffers::Vector *value_indices, ET_NODISCARD Result getTensorDataPtr(const executorch_flatbuffer::Tensor *s_tensor, const Program *program, size_t nbytes, - HierarchicalAllocator *allocator); + HierarchicalAllocator *allocator, + const NamedDataMap *named_data_map = nullptr, + Span external_constants = {}); } // namespace deserialization } // namespace runtime @@ -114,3 +150,7 @@ using ::executorch::runtime::deserialization::parseTensorList; } // namespace deserialization } // namespace executor } // namespace torch + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/third-party/include/executorch/runtime/kernel/kernel_runtime_context.h b/third-party/include/executorch/runtime/kernel/kernel_runtime_context.h index e6367da9dc..04e00e2b83 100644 --- a/third-party/include/executorch/runtime/kernel/kernel_runtime_context.h +++ b/third-party/include/executorch/runtime/kernel/kernel_runtime_context.h @@ -117,6 +117,6 @@ namespace aten { using RuntimeContext = ::executorch::runtime::KernelRuntimeContext; } // namespace aten } // namespace executorch -// DEPRECATED: The exec_aten:: namespace is deprecated. Use executorch::aten:: -// instead. +// DEPRECATED: The executorch::aten:: namespace is deprecated. Use +// executorch::aten:: instead. namespace exec_aten = ::executorch::aten; diff --git a/third-party/include/executorch/runtime/kernel/operator_registry.h b/third-party/include/executorch/runtime/kernel/operator_registry.h index 095a674215..92a7504193 100644 --- a/third-party/include/executorch/runtime/kernel/operator_registry.h +++ b/third-party/include/executorch/runtime/kernel/operator_registry.h @@ -25,15 +25,15 @@ #endif #define ET_LOG_KERNEL_KEY(k) \ - ET_LOG(Error, "key: %s, is_fallback: %s", k.data(), \ + ET_LOG(Info, "key: %s, is_fallback: %s", k.data(), \ k.is_fallback() ? "true" : "false"); #define ET_LOG_TENSOR_META(meta_list) \ for (const auto &meta : meta_list) { \ - ET_LOG(Error, "dtype: %d | dim order: [", int(meta.dtype_)); \ - for (int i = 0; i < meta.dim_order_.size(); i++) { \ - ET_LOG(Error, "%d,", static_cast(meta.dim_order_[i])); \ + ET_LOG(Info, "dtype: %d | dim order: [", int(meta.dtype_)); \ + for (size_t i = 0; i < meta.dim_order_.size(); i++) { \ + ET_LOG(Info, "%d,", static_cast(meta.dim_order_[i])); \ } \ - ET_LOG(Error, "]"); \ + ET_LOG(Info, "]"); \ } namespace executorch { @@ -68,7 +68,7 @@ struct TensorMeta { if (dim_order_.size() != other.dim_order_.size()) { return false; } - for (int i = 0; i < dim_order_.size(); i++) { + for (size_t i = 0; i < dim_order_.size(); i++) { if (dim_order_[i] != other.dim_order_[i]) { return false; } @@ -90,25 +90,21 @@ struct TensorMeta { /** * Describes which dtype & dim order specialized kernel to be bound to an - * operator. If `is_fallback_` is true, it means this kernel can be used as a - * fallback, if false, it means this kernel can only be used if all the - * `TensorMeta` are matched. Fallback means this kernel will be used for - * all input tensor dtypes and dim orders, if the specialized kernel is not - * registered. + * operator. * - * The format of a kernel key data is a string: - * "v/|..." - * Size: Up to 691 1 1 1 (42 +1) * 16 - * Assuming max number of tensors is 16 ^ - * Kernel key version is v1 for now. If the kernel key format changes, - * update the version to avoid breaking pre-existing kernel keys. - * Example: v1/7;0,1,2,3 - * The kernel key has only one tensor: a double tensor with dimension 0, 1, 2, 3 + * Kernel key data is a string with the format: + * + * "v/|..." + * + * The version is v1 for now. If the kernel key format changes, update the + * version to avoid breaking pre-existing kernel keys. * * Each tensor_meta has the following format: ";" - * Size: Up to 42 1-2 1 24 (1 byte for 0-9; 2 - * for 10-15) + 15 commas Assuming that the max number of dims is 16 ^ Example: - * 7;0,1,2,3 for [double; 0, 1, 2, 3] + * + * Example kernel key data: "v1/7;0,1,2,3|1;0,1,2,3,4,5,6,7" + * + * This has two tensors: the first with dtype=7 and dim order 0,1,2,3, and the + * second with dtype=1 and dim order 0,1,2,3,4,5,6,7. * * IMPORTANT: * Users should not construct a kernel key manually. Instead, it should be @@ -116,13 +112,21 @@ struct TensorMeta { */ struct KernelKey { public: + /** + * Creates a fallback (non-specialized) kernel key: this kernel can be used + * for all input tensor dtypes and dim orders if the specialized kernel is not + * registered. + */ KernelKey() : is_fallback_(true) {} + /** + * Creates a specialized (non-fallback) kernel key that matches a specific + * set of input tensor dtypes and dim orders. See the class comment for the + * expected format of `kernel_key_data`. + */ /* implicit */ KernelKey(const char *kernel_key_data) : kernel_key_data_(kernel_key_data), is_fallback_(false) {} - constexpr static int MAX_SIZE = 691; - bool operator==(const KernelKey &other) const { return this->equals(other); } bool operator!=(const KernelKey &other) const { return !this->equals(other); } @@ -134,7 +138,7 @@ struct KernelKey { if (is_fallback_) { return true; } - return strncmp(kernel_key_data_, other.kernel_key_data_, MAX_SIZE) == 0; + return strcmp(kernel_key_data_, other.kernel_key_data_) == 0; } bool is_fallback() const { return is_fallback_; } @@ -180,7 +184,21 @@ struct Kernel { }; namespace internal { -void make_kernel_key_string(Span key, char *buf); + +/** + * A make_kernel_key_string buffer size that is large enough to hold a kernel + * key string with 16 tensors of 16 dimensions, plus the trailing NUL byte. + */ +constexpr size_t kKernelKeyBufSize = 659; + +/** + * Given the list of input tensor dtypes + dim orders, writes the kernel key + * string into the buffer. Returns an error if the buffer is too small or if the + * tensors cannot be represented as a valid key string. + */ +Error make_kernel_key_string(Span key, char *buf, + size_t buf_size); + } // namespace internal /** diff --git a/third-party/include/executorch/runtime/platform/compat_unistd.h b/third-party/include/executorch/runtime/platform/compat_unistd.h new file mode 100644 index 0000000000..c7bd513d5d --- /dev/null +++ b/third-party/include/executorch/runtime/platform/compat_unistd.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @file + * unistd.h related macros for POSIX/Windows compatibility. + */ +#pragma once + +#if defined(_WIN32) && !defined(_WIN64) +#error \ + "You're trying to build ExecuTorch with a too old version of Windows. We need Windows 64-bit." +#endif + +#if !defined(_WIN64) +#include +#else +#include +#define O_RDONLY _O_RDONLY +#define open _open +#define close _close +#define read _read +#define write _write +#define stat _stat64 +#define fstat _fstat64 +#define off_t _off_t +#define lseek _lseeki64 + +#include // For ssize_t. +#include +// To avoid conflicts with std::numeric_limits::max() in +// file_data_loader.cpp. +#undef max + +inline ssize_t pread(int fd, void *buf, size_t nbytes, size_t offset) { + OVERLAPPED overlapped; /* The offset for ReadFile. */ + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.Offset = offset; + overlapped.OffsetHigh = offset >> 32; + + BOOL result; /* The result of ReadFile. */ + DWORD bytes_read; /* The number of bytes read. */ + HANDLE file = (HANDLE)_get_osfhandle(fd); + + result = ReadFile(file, buf, nbytes, &bytes_read, &overlapped); + DWORD error = GetLastError(); + if (!result) { + if (error == ERROR_IO_PENDING) { + result = GetOverlappedResult(file, &overlapped, &bytes_read, TRUE); + if (!result) { + error = GetLastError(); + } + } + } + if (!result) { + // Translate error into errno. + switch (error) { + case ERROR_HANDLE_EOF: + errno = 0; + break; + default: + errno = EIO; + break; + } + return -1; + } + return bytes_read; +} + +#endif // !defined(_WIN64) \ No newline at end of file diff --git a/third-party/include/executorch/runtime/platform/compiler.h b/third-party/include/executorch/runtime/platform/compiler.h index 6e98906b96..f6d45e9792 100644 --- a/third-party/include/executorch/runtime/platform/compiler.h +++ b/third-party/include/executorch/runtime/platform/compiler.h @@ -146,6 +146,13 @@ #define ET_FUNCTION __FUNCTION__ #endif // __has_builtin(__builtin_FUNCTION) +// As of G3 RJ-2024.3 toolchain, zu format specifier is not supported for Xtensa +#if defined(__XTENSA__) +#define ET_PRIsize_t "lu" +#else +#define ET_PRIsize_t "zu" +#endif + // Whether the compiler supports GNU statement expressions. // https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html #ifndef ET_HAVE_GNU_STATEMENT_EXPRESSIONS diff --git a/third-party/include/executorch/runtime/platform/log.h b/third-party/include/executorch/runtime/platform/log.h index 3bcbce7c56..d4326750c7 100644 --- a/third-party/include/executorch/runtime/platform/log.h +++ b/third-party/include/executorch/runtime/platform/log.h @@ -33,6 +33,15 @@ #define ET_LOG_ENABLED 1 #endif // !defined(ET_LOG_ENABLED) +// Even though it is supposed to be "portable" some toolchains +// do not define, so providing a definition here +#ifndef PRIu64 +#define PRIu64 "llu" +#endif +#ifndef PRId64 +#define PRId64 "lld" +#endif + namespace executorch { namespace runtime { diff --git a/third-party/include/opencv2/core.hpp b/third-party/include/opencv2/core.hpp new file mode 100644 index 0000000000..c3e83ae17b --- /dev/null +++ b/third-party/include/opencv2/core.hpp @@ -0,0 +1,3699 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this +license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2015, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +// Copyright (C) 2015, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright +notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote +products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" +and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are +disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any +direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_HPP +#define OPENCV_CORE_HPP + +#ifndef __cplusplus +#error core.hpp header must be compiled as C++ +#endif + +#include "opencv2/core/base.hpp" +#include "opencv2/core/cvdef.h" +#include "opencv2/core/cvstd.hpp" +#include "opencv2/core/mat.hpp" +#include "opencv2/core/matx.hpp" +#include "opencv2/core/persistence.hpp" +#include "opencv2/core/traits.hpp" +#include "opencv2/core/types.hpp" + +/** +@defgroup core Core functionality + +The Core module is the backbone of OpenCV, offering fundamental data structures, +matrix operations, and utility functions that other modules depend on. It’s +essential for handling image data, performing mathematical computations, and +managing memory efficiently within the OpenCV ecosystem. + +@{ + @defgroup core_basic Basic structures + @defgroup core_array Operations on arrays + @defgroup core_async Asynchronous API + @defgroup core_xml XML/YAML/JSON Persistence + @defgroup core_cluster Clustering + @defgroup core_utils Utility and system functions and macros + @{ + @defgroup core_logging Logging facilities + @defgroup core_utils_sse SSE utilities + @defgroup core_utils_neon NEON utilities + @defgroup core_utils_vsx VSX utilities + @defgroup core_utils_softfloat Softfloat support + @defgroup core_utils_samples Utility functions for OpenCV samples + @} + @defgroup core_opengl OpenGL interoperability + @defgroup core_optim Optimization Algorithms + @defgroup core_directx DirectX interoperability + @defgroup core_eigen Eigen support + @defgroup core_opencl OpenCL support + @defgroup core_va_intel Intel VA-API/OpenCL (CL-VA) interoperability + @defgroup core_hal Hardware Acceleration Layer + @{ + @defgroup core_hal_functions Functions + @defgroup core_hal_interface Interface + @defgroup core_hal_intrin Universal intrinsics + @{ + @defgroup core_hal_intrin_impl Private implementation helpers + @} + @defgroup core_lowlevel_api Low-level API for external libraries / +plugins + @} + @defgroup core_parallel Parallel Processing + @{ + @defgroup core_parallel_backend Parallel backends API + @} + @defgroup core_quaternion Quaternion +@} + */ + +namespace cv { + +//! @addtogroup core_utils +//! @{ + +/*! @brief Class passed to an error. + +This class encapsulates all or almost all necessary +information about the error happened in the program. The exception is +usually constructed and thrown implicitly via CV_Error and CV_Error_ macros. +@see error + */ +class CV_EXPORTS Exception : public std::exception { +public: + /*! + Default constructor + */ + Exception(); + /*! + Full constructor. Normally the constructor is not called explicitly. + Instead, the macros CV_Error(), CV_Error_() and CV_Assert() are used. + */ + Exception(int _code, const String &_err, const String &_func, + const String &_file, int _line); + virtual ~Exception() CV_NOEXCEPT; + + /*! + \return the error description and the context as a text string. + */ + virtual const char *what() const CV_NOEXCEPT CV_OVERRIDE; + void formatMessage(); + + String msg; ///< the formatted error message + + int code; ///< error code @see CVStatus + String err; ///< error description + String func; ///< function name. Available only when the compiler supports + ///< getting it + String file; ///< source file name where the error has occurred + int line; ///< line number in the source file where the error has occurred +}; + +/*! @brief Signals an error and raises the exception. + +By default the function prints information about the error to stderr, +then it either stops if cv::setBreakOnError() had been called before or raises +the exception. It is possible to alternate error processing by using +#redirectError(). +@param exc the exception raisen. +@deprecated drop this version + */ +CV_EXPORTS CV_NORETURN void error(const Exception &exc); + +enum SortFlags { + SORT_EVERY_ROW = 0, //!< each matrix row is sorted independently + SORT_EVERY_COLUMN = 1, //!< each matrix column is sorted + //!< independently; this flag and the previous one are + //!< mutually exclusive. + SORT_ASCENDING = 0, //!< each matrix row is sorted in the ascending + //!< order. + SORT_DESCENDING = 16 //!< each matrix row is sorted in the + //!< descending order; this flag and the previous one are + //!< also mutually exclusive. +}; + +//! @} core_utils + +//! @addtogroup core_array +//! @{ + +//! Covariation flags +enum CovarFlags { + /** The output covariance matrix is calculated as: + \f[\texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , + \texttt{vects} [1]- \texttt{mean} ,...]^T \cdot [ \texttt{vects} [0]- + \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...],\f] The + covariance matrix will be nsamples x nsamples. Such an unusual covariance + matrix is used for fast PCA of a set of very large vectors (see, for + example, the EigenFaces technique for face recognition). Eigenvalues of + this "scrambled" matrix match the eigenvalues of the true covariance + matrix. The "true" eigenvectors can be easily calculated from the + eigenvectors of the "scrambled" covariance matrix. */ + COVAR_SCRAMBLED = 0, + /**The output covariance matrix is calculated as: + \f[\texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , + \texttt{vects} [1]- \texttt{mean} ,...] \cdot [ \texttt{vects} [0]- + \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...]^T,\f] covar will + be a square matrix of the same size as the total number of elements in each + input vector. One and only one of #COVAR_SCRAMBLED and #COVAR_NORMAL must + be specified.*/ + COVAR_NORMAL = 1, + /** If the flag is specified, the function does not calculate mean from + the input vectors but, instead, uses the passed mean vector. This is + useful if mean has been pre-calculated or known in advance, or if the + covariance matrix is calculated by parts. In this case, mean is not a mean + vector of the input sub-set of vectors but rather the mean vector of the + whole set.*/ + COVAR_USE_AVG = 2, + /** If the flag is specified, the covariance matrix is scaled. In the + "normal" mode, scale is 1./nsamples . In the "scrambled" mode, scale is + the reciprocal of the total number of elements in each input vector. By + default (if the flag is not specified), the covariance matrix is not scaled + ( scale=1 ).*/ + COVAR_SCALE = 4, + /** If the flag is + specified, all the input vectors are stored as rows of the samples matrix. + mean should be a single-row vector in this case.*/ + COVAR_ROWS = 8, + /** If the flag is + specified, all the input vectors are stored as columns of the samples + matrix. mean should be a single-column vector in this case.*/ + COVAR_COLS = 16 +}; + +enum ReduceTypes { + REDUCE_SUM = 0, //!< the output is the sum of all rows/columns of the matrix. + REDUCE_AVG = + 1, //!< the output is the mean vector of all rows/columns of the matrix. + REDUCE_MAX = 2, //!< the output is the maximum (column/row-wise) of all + //!< rows/columns of the matrix. + REDUCE_MIN = 3, //!< the output is the minimum (column/row-wise) of all + //!< rows/columns of the matrix. + REDUCE_SUM2 = + 4 //!< the output is the sum of all squared rows/columns of the matrix. +}; + +/** @brief Swaps two matrices + */ +CV_EXPORTS void swap(Mat &a, Mat &b); + +/** @brief Computes the source location of an extrapolated pixel. + +The function computes and returns the coordinate of a donor pixel corresponding +to the specified extrapolated pixel when using the specified extrapolation +border mode. For example, if you use cv::BORDER_WRAP mode in the horizontal +direction, cv::BORDER_REFLECT_101 in the vertical direction and want to compute +value of the "virtual" pixel Point(-5, 100) in a floating-point image img, it +looks like: +@code{.cpp} + float val = img.at(borderInterpolate(100, img.rows, +cv::BORDER_REFLECT_101), borderInterpolate(-5, img.cols, cv::BORDER_WRAP)); +@endcode +Normally, the function is not called directly. It is used inside filtering +functions and also in copyMakeBorder. +@param p 0-based coordinate of the extrapolated pixel along one of the axes, +likely \<0 or \>= len +@param len Length of the array along the corresponding axis. +@param borderType Border type, one of the #BorderTypes, except for +#BORDER_TRANSPARENT and #BORDER_ISOLATED. When borderType==#BORDER_CONSTANT, the +function always returns -1, regardless of p and len. + +@sa copyMakeBorder +*/ +CV_EXPORTS_W int borderInterpolate(int p, int len, int borderType); + +/** @example samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp +An example using copyMakeBorder function. +Check @ref tutorial_copyMakeBorder "the corresponding tutorial" for more details +*/ + +/** @brief Forms a border around an image. + +The function copies the source image into the middle of the destination image. +The areas to the left, to the right, above and below the copied source image +will be filled with extrapolated pixels. This is not what filtering functions +based on it do (they extrapolate pixels on-fly), but what other more complex +functions, including your own, may do to simplify image boundary handling. + +The function supports the mode when src is already in the middle of dst . In +this case, the function does not copy src itself but simply constructs the +border, for example: + +@code{.cpp} + // let border be the same in all directions + int border=2; + // constructs a larger image to fit both the image and the border + Mat gray_buf(rgb.rows + border*2, rgb.cols + border*2, rgb.depth()); + // select the middle part of it w/o copying data + Mat gray(gray_canvas, Rect(border, border, rgb.cols, rgb.rows)); + // convert image from RGB to grayscale + cvtColor(rgb, gray, COLOR_RGB2GRAY); + // form a border in-place + copyMakeBorder(gray, gray_buf, border, border, + border, border, BORDER_REPLICATE); + // now do some custom filtering ... + ... +@endcode +@note When the source image is a part (ROI) of a bigger image, the function will +try to use the pixels outside of the ROI to form a border. To disable this +feature and always do extrapolation, as if src was not a ROI, use borderType | +#BORDER_ISOLATED. + +@param src Source image. +@param dst Destination image of the same type as src and the size +Size(src.cols+left+right, src.rows+top+bottom) . +@param top the top pixels +@param bottom the bottom pixels +@param left the left pixels +@param right Parameter specifying how many pixels in each direction from the +source image rectangle to extrapolate. For example, top=1, bottom=1, left=1, +right=1 mean that 1 pixel-wide border needs to be built. +@param borderType Border type. See borderInterpolate for details. +@param value Border value if borderType==BORDER_CONSTANT . + +@sa borderInterpolate +*/ +CV_EXPORTS_W void copyMakeBorder(InputArray src, OutputArray dst, int top, + int bottom, int left, int right, + int borderType, + const Scalar &value = Scalar()); + +/** @brief Calculates the per-element sum of two arrays or an array and a +scalar. + +The function add calculates: +- Sum of two arrays when both input arrays have the same size and the same +number of channels: +\f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2}(I)) +\quad \texttt{if mask}(I) \ne0\f] +- Sum of an array and a scalar when src2 is constructed from Scalar or has the +same number of elements as `src1.channels()`: +\f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2} ) +\quad \texttt{if mask}(I) \ne0\f] +- Sum of a scalar and an array when src1 is constructed from Scalar or has the +same number of elements as `src2.channels()`: +\f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1} + \texttt{src2}(I) ) +\quad \texttt{if mask}(I) \ne0\f] where `I` is a multi-dimensional index of +array elements. In case of multi-channel arrays, each channel is processed +independently. + +The first function in the list above can be replaced with matrix expressions: +@code{.cpp} + dst = src1 + src2; + dst += src1; // equivalent to add(dst, src1, dst); +@endcode +The input arrays and the output array can all have the same or different depths. +For example, you can add a 16-bit unsigned array to a 8-bit signed array and +store the sum as a 32-bit floating-point array. Depth of the output array is +determined by the dtype parameter. In the second and third cases above, as well +as in the first case, when src1.depth() == src2.depth(), dtype can be set to the +default -1. In this case, the output array will have the same depth as the input +array, be it src1, src2 or both. +@note Saturation is not applied when the output array has the depth CV_32S. You +may even get result of an incorrect sign in the case of overflow. +@note (Python) Be careful to difference behaviour between src1/src2 are single +number and they are tuple/array. `add(src,X)` means `add(src,(X,X,X,X))`. +`add(src,(X,))` means `add(src,(X,0,0,0))`. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and number of channels as the +input array(s); the depth is defined by dtype or src1/src2. +@param mask optional operation mask - 8-bit single channel array, that specifies +elements of the output array to be changed. +@param dtype optional depth of the output array (see the discussion below). +@sa subtract, addWeighted, scaleAdd, Mat::convertTo +*/ +CV_EXPORTS_W void add(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask = noArray(), int dtype = -1); + +/** @brief Calculates the per-element difference between two arrays or array and +a scalar. + +The function subtract calculates: +- Difference between two arrays, when both input arrays have the same size and +the same number of channels: + \f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - +\texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0\f] +- Difference between an array and a scalar, when src2 is constructed from Scalar +or has the same number of elements as `src1.channels()`: + \f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - \texttt{src2} +) \quad \texttt{if mask}(I) \ne0\f] +- Difference between a scalar and an array, when src1 is constructed from Scalar +or has the same number of elements as `src2.channels()`: + \f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src1} - \texttt{src2}(I) +) \quad \texttt{if mask}(I) \ne0\f] +- The reverse difference between a scalar and an array in the case of `SubRS`: + \f[\texttt{dst}(I) = \texttt{saturate} ( \texttt{src2} - \texttt{src1}(I) +) \quad \texttt{if mask}(I) \ne0\f] where I is a multi-dimensional index of +array elements. In case of multi-channel arrays, each channel is processed +independently. + +The first function in the list above can be replaced with matrix expressions: +@code{.cpp} + dst = src1 - src2; + dst -= src1; // equivalent to subtract(dst, src1, dst); +@endcode +The input arrays and the output array can all have the same or different depths. +For example, you can subtract to 8-bit unsigned arrays and store the difference +in a 16-bit signed array. Depth of the output array is determined by dtype +parameter. In the second and third cases above, as well as in the first case, +when src1.depth() == src2.depth(), dtype can be set to the default -1. In this +case the output array will have the same depth as the input array, be it src1, +src2 or both. +@note Saturation is not applied when the output array has the depth CV_32S. You +may even get result of an incorrect sign in the case of overflow. +@note (Python) Be careful to difference behaviour between src1/src2 are single +number and they are tuple/array. `subtract(src,X)` means +`subtract(src,(X,X,X,X))`. `subtract(src,(X,))` means `subtract(src,(X,0,0,0))`. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array of the same size and the same number of channels as the +input array. +@param mask optional operation mask; this is an 8-bit single channel array that +specifies elements of the output array to be changed. +@param dtype optional depth of the output array +@sa add, addWeighted, scaleAdd, Mat::convertTo + */ +CV_EXPORTS_W void subtract(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask = noArray(), int dtype = -1); + +/** @brief Calculates the per-element scaled product of two arrays. + +The function multiply calculates the per-element product of two arrays: + +\f[\texttt{dst} (I)= \texttt{saturate} ( \texttt{scale} \cdot \texttt{src1} (I) +\cdot \texttt{src2} (I))\f] + +There is also a @ref MatrixExpressions -friendly variant of the first function. +See Mat::mul . + +For a not-per-element matrix product, see gemm . + +@note Saturation is not applied when the output array has the depth +CV_32S. You may even get result of an incorrect sign in the case of +overflow. +@note (Python) Be careful to difference behaviour between src1/src2 are single +number and they are tuple/array. `multiply(src,X)` means +`multiply(src,(X,X,X,X))`. `multiply(src,(X,))` means `multiply(src,(X,0,0,0))`. +@param src1 first input array. +@param src2 second input array of the same size and the same type as src1. +@param dst output array of the same size and type as src1. +@param scale optional scale factor. +@param dtype optional depth of the output array +@sa add, subtract, divide, scaleAdd, addWeighted, accumulate, accumulateProduct, +accumulateSquare, Mat::convertTo +*/ +CV_EXPORTS_W void multiply(InputArray src1, InputArray src2, OutputArray dst, + double scale = 1, int dtype = -1); + +/** @brief Performs per-element division of two arrays or a scalar by an array. + +The function cv::divide divides one array by another: +\f[\texttt{dst(I) = saturate(src1(I)*scale/src2(I))}\f] +or a scalar by an array when there is no src1 : +\f[\texttt{dst(I) = saturate(scale/src2(I))}\f] + +Different channels of multi-channel arrays are processed independently. + +For integer types when src2(I) is zero, dst(I) will also be zero. + +@note In case of floating point data there is no special defined behavior for +zero src2(I) values. Regular floating-point division is used. Expect correct +IEEE-754 behaviour for floating-point data (with NaN, Inf result values). + +@note Saturation is not applied when the output array has the depth CV_32S. You +may even get result of an incorrect sign in the case of overflow. +@note (Python) Be careful to difference behaviour between src1/src2 are single +number and they are tuple/array. `divide(src,X)` means `divide(src,(X,X,X,X))`. +`divide(src,(X,))` means `divide(src,(X,0,0,0))`. +@param src1 first input array. +@param src2 second input array of the same size and type as src1. +@param scale scalar factor. +@param dst output array of the same size and type as src2. +@param dtype optional depth of the output array; if -1, dst will have depth +src2.depth(), but in case of an array-by-array division, you can only pass -1 +when src1.depth()==src2.depth(). +@sa multiply, add, subtract +*/ +CV_EXPORTS_W void divide(InputArray src1, InputArray src2, OutputArray dst, + double scale = 1, int dtype = -1); + +/** @overload */ +CV_EXPORTS_W void divide(double scale, InputArray src2, OutputArray dst, + int dtype = -1); + +/** @brief Calculates the sum of a scaled array and another array. + +The function scaleAdd is one of the classical primitive linear algebra +operations, known as DAXPY or SAXPY in +[BLAS](http://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms). It +calculates the sum of a scaled array and another array: +\f[\texttt{dst} (I)= \texttt{scale} \cdot \texttt{src1} (I) + \texttt{src2} +(I)\f] The function can also be emulated with a matrix expression, for example: +@code{.cpp} + Mat A(3, 3, CV_64F); + ... + A.row(0) = A.row(1)*2 + A.row(2); +@endcode +@param src1 first input array. +@param alpha scale factor for the first array. +@param src2 second input array of the same size and type as src1. +@param dst output array of the same size and type as src1. +@sa add, addWeighted, subtract, Mat::dot, Mat::convertTo +*/ +CV_EXPORTS_W void scaleAdd(InputArray src1, double alpha, InputArray src2, + OutputArray dst); + +/** @brief Calculates the weighted sum of two arrays. + +The function addWeighted calculates the weighted sum of two arrays as follows: +\f[\texttt{dst} (I)= \texttt{saturate} ( \texttt{src1} (I)* \texttt{alpha} + +\texttt{src2} (I)* \texttt{beta} + \texttt{gamma} )\f] where I is a +multi-dimensional index of array elements. In case of multi-channel arrays, each +channel is processed independently. +The function can be replaced with a matrix expression: +@code{.cpp} + dst = src1*alpha + src2*beta + gamma; +@endcode +@note Saturation is not applied when the output array has the depth CV_32S. You +may even get result of an incorrect sign in the case of overflow. +@param src1 first input array. +@param alpha weight of the first array elements. +@param src2 second input array of the same size and channel number as src1. +@param beta weight of the second array elements. +@param gamma scalar added to each sum. +@param dst output array that has the same size and number of channels as the +input arrays. +@param dtype optional depth of the output array; when both input arrays have the +same depth, dtype can be set to -1, which will be equivalent to src1.depth(). +@sa add, subtract, scaleAdd, Mat::convertTo +*/ +CV_EXPORTS_W void addWeighted(InputArray src1, double alpha, InputArray src2, + double beta, double gamma, OutputArray dst, + int dtype = -1); + +/** @brief Scales, calculates absolute values, and converts the result to 8-bit. + +On each element of the input array, the function convertScaleAbs +performs three operations sequentially: scaling, taking an absolute +value, conversion to an unsigned 8-bit type: +\f[\texttt{dst} (I)= \texttt{saturate\_cast} (| \texttt{src} (I)* +\texttt{alpha} + \texttt{beta} |)\f] In case of multi-channel arrays, the +function processes each channel independently. When the output is not 8-bit, the +operation can be emulated by calling the Mat::convertTo method (or by using +matrix expressions) and then by calculating an absolute value of the result. For +example: +@code{.cpp} + Mat_ A(30,30); + randu(A, Scalar(-100), Scalar(100)); + Mat_ B = A*5 + 3; + B = abs(B); + // Mat_ B = abs(A*5+3) will also do the job, + // but it will allocate a temporary matrix +@endcode +@param src input array. +@param dst output array. +@param alpha optional scale factor. +@param beta optional delta added to the scaled values. +@sa Mat::convertTo, cv::abs(const Mat&) +*/ +CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst, + double alpha = 1, double beta = 0); + +/** @brief Converts an array to half precision floating number. + +This function converts FP32 (single precision floating point) from/to FP16 (half +precision floating point). CV_16S format is used to represent FP16 data. There +are two use modes (src -> dst): CV_32F -> CV_16S and CV_16S -> CV_32F. The input +array has to have type of CV_32F or CV_16S to represent the bit depth. If the +input array is neither of them, the function will raise an error. The format of +half precision floating point is defined in IEEE 754-2008. + +@param src input array. +@param dst output array. + +@deprecated Use Mat::convertTo with CV_16F instead. +*/ +CV_EXPORTS_W void convertFp16(InputArray src, OutputArray dst); + +/** @example +samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp Check +@ref tutorial_how_to_scan_images "the corresponding tutorial" for more details +*/ + +/** @brief Performs a look-up table transform of an array. + +The function LUT fills the output array with values from the look-up table. +Indices of the entries are taken from the input array. That is, the function +processes each element of src as follows: +\f[\texttt{dst} (I) \leftarrow \texttt{lut(src(I) + d)}\f] +where +\f[d = \fork{0}{if \(\texttt{src}\) has depth \(\texttt{CV_8U}\)}{128}{if +\(\texttt{src}\) has depth \(\texttt{CV_8S}\)}\f] +@param src input array of 8-bit elements. +@param lut look-up table of 256 elements; in case of multi-channel input array, +the table should either have a single channel (in this case the same table is +used for all channels) or the same number of channels as in the input array. +@param dst output array of the same size and number of channels as src, and the +same depth as lut. +@sa convertScaleAbs, Mat::convertTo +*/ +CV_EXPORTS_W void LUT(InputArray src, InputArray lut, OutputArray dst); + +/** @brief Calculates the sum of array elements. + +The function cv::sum calculates and returns the sum of array elements, +independently for each channel. +@param src input array that must have from 1 to 4 channels. +@sa countNonZero, mean, meanStdDev, norm, minMaxLoc, reduce +*/ +CV_EXPORTS_AS(sumElems) Scalar sum(InputArray src); + +/** @brief Checks for the presence of at least one non-zero array element. + +The function returns whether there are non-zero elements in src + +The function do not work with multi-channel arrays. If you need to check +non-zero array elements across all the channels, use Mat::reshape first to +reinterpret the array as single-channel. Or you may extract the particular +channel using either extractImageCOI, or mixChannels, or split. + +@note +- If the location of non-zero array elements is important, @ref findNonZero is +helpful. +- If the count of non-zero array elements is important, @ref countNonZero is +helpful. +@param src single-channel array. +@sa mean, meanStdDev, norm, minMaxLoc, calcCovarMatrix +@sa findNonZero, countNonZero +*/ +CV_EXPORTS_W bool hasNonZero(InputArray src); + +/** @brief Counts non-zero array elements. + +The function returns the number of non-zero elements in src : +\f[\sum _{I: \; \texttt{src} (I) \ne0 } 1\f] + +The function do not work with multi-channel arrays. If you need to count +non-zero array elements across all the channels, use Mat::reshape first to +reinterpret the array as single-channel. Or you may extract the particular +channel using either extractImageCOI, or mixChannels, or split. + +@note +- If only whether there are non-zero elements is important, @ref hasNonZero is +helpful. +- If the location of non-zero array elements is important, @ref findNonZero is +helpful. +@param src single-channel array. +@sa mean, meanStdDev, norm, minMaxLoc, calcCovarMatrix +@sa findNonZero, hasNonZero +*/ +CV_EXPORTS_W int countNonZero(InputArray src); + +/** @brief Returns the list of locations of non-zero pixels + +Given a binary matrix (likely returned from an operation such +as threshold(), compare(), >, ==, etc, return all of +the non-zero indices as a cv::Mat or std::vector (x,y) +For example: +@code{.cpp} + cv::Mat binaryImage; // input, binary image + cv::Mat locations; // output, locations of non-zero pixels + cv::findNonZero(binaryImage, locations); + + // access pixel coordinates + Point pnt = locations.at(i); +@endcode +or +@code{.cpp} + cv::Mat binaryImage; // input, binary image + vector locations; // output, locations of non-zero pixels + cv::findNonZero(binaryImage, locations); + + // access pixel coordinates + Point pnt = locations[i]; +@endcode + +The function do not work with multi-channel arrays. If you need to find non-zero +elements across all the channels, use Mat::reshape first to reinterpret the +array as single-channel. Or you may extract the particular channel using either +extractImageCOI, or mixChannels, or split. + +@note +- If only count of non-zero array elements is important, @ref countNonZero is +helpful. +- If only whether there are non-zero elements is important, @ref hasNonZero is +helpful. +@param src single-channel array +@param idx the output array, type of cv::Mat or std::vector, +corresponding to non-zero indices in the input +@sa countNonZero, hasNonZero +*/ +CV_EXPORTS_W void findNonZero(InputArray src, OutputArray idx); + +/** @brief Calculates an average (mean) of array elements. + +The function cv::mean calculates the mean value M of array elements, +independently for each channel, and return it: +\f[\begin{array}{l} N = \sum _{I: \; \texttt{mask} (I) \ne 0} 1 \\ M_c = \left +( \sum _{I: \; \texttt{mask} (I) \ne 0}{ \texttt{mtx} (I)_c} \right )/N +\end{array}\f] When all the mask elements are 0's, the function returns +Scalar::all(0) +@param src input array that should have from 1 to 4 channels so that the result +can be stored in Scalar_ . +@param mask optional operation mask. +@sa countNonZero, meanStdDev, norm, minMaxLoc +*/ +CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask = noArray()); + +/** Calculates a mean and standard deviation of array elements. + +The function cv::meanStdDev calculates the mean and the standard deviation M +of array elements independently for each channel and returns it via the +output parameters: +\f[\begin{array}{l} N = \sum _{I, \texttt{mask} (I) \ne 0} 1 \\ \texttt{mean} +_c = \frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \texttt{src} (I)_c}{N} +\\ \texttt{stddev} _c = \sqrt{\frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \left +( \texttt{src} (I)_c - \texttt{mean} _c \right )^2}{N}} \end{array}\f] When all +the mask elements are 0's, the function returns mean=stddev=Scalar::all(0). +@note The calculated standard deviation is only the diagonal of the +complete normalized covariance matrix. If the full matrix is needed, you +can reshape the multi-channel array M x N to the single-channel array +M\*N x mtx.channels() (only possible when the matrix is continuous) and +then pass the matrix to calcCovarMatrix . +@param src input array that should have from 1 to 4 channels so that the results +can be stored in Scalar_ 's. +@param mean output parameter: calculated mean value. +@param stddev output parameter: calculated standard deviation. +@param mask optional operation mask. +@sa countNonZero, mean, norm, minMaxLoc, calcCovarMatrix +*/ +CV_EXPORTS_W void meanStdDev(InputArray src, OutputArray mean, + OutputArray stddev, InputArray mask = noArray()); + +/** @brief Calculates the absolute norm of an array. + +This version of #norm calculates the absolute norm of src1. The type of norm to +calculate is specified using #NormTypes. + +As example for one array consider the function \f$r(x)= \begin{pmatrix} x \\ 1-x +\end{pmatrix}, x \in [-1;1]\f$. The \f$ L_{1}, L_{2} \f$ and \f$ L_{\infty} \f$ +norm for the sample value \f$r(-1) = \begin{pmatrix} -1 \\ 2 \end{pmatrix}\f$ is +calculated as follows +\f{align*} + \| r(-1) \|_{L_1} &= |-1| + |2| = 3 \\ + \| r(-1) \|_{L_2} &= \sqrt{(-1)^{2} + (2)^{2}} = \sqrt{5} \\ + \| r(-1) \|_{L_\infty} &= \max(|-1|,|2|) = 2 +\f} +and for \f$r(0.5) = \begin{pmatrix} 0.5 \\ 0.5 \end{pmatrix}\f$ the calculation +is +\f{align*} + \| r(0.5) \|_{L_1} &= |0.5| + |0.5| = 1 \\ + \| r(0.5) \|_{L_2} &= \sqrt{(0.5)^{2} + (0.5)^{2}} = \sqrt{0.5} \\ + \| r(0.5) \|_{L_\infty} &= \max(|0.5|,|0.5|) = 0.5. +\f} +The following graphic shows all values for the three norm functions \f$\| r(x) +\|_{L_1}, \| r(x) \|_{L_2}\f$ and \f$\| r(x) \|_{L_\infty}\f$. It is notable +that the \f$ L_{1} \f$ norm forms the upper and the \f$ L_{\infty} \f$ norm +forms the lower border for the example function \f$ r(x) \f$. +![Graphs for the different norm functions from the above +example](pics/NormTypes_OneArray_1-2-INF.png) + +When the mask parameter is specified and it is not empty, the norm is + +If normType is not specified, #NORM_L2 is used. +calculated only over the region specified by the mask. + +Multi-channel input arrays are treated as single-channel arrays, that is, +the results for all channels are combined. + +Hamming norms can only be calculated with CV_8U depth arrays. + +@param src1 first input array. +@param normType type of the norm (see #NormTypes). +@param mask optional operation mask; it must have the same size as src1 and +CV_8UC1 type. +*/ +CV_EXPORTS_W double norm(InputArray src1, int normType = NORM_L2, + InputArray mask = noArray()); + +/** @brief Calculates an absolute difference norm or a relative difference norm. + +This version of cv::norm calculates the absolute difference norm +or the relative difference norm of arrays src1 and src2. +The type of norm to calculate is specified using #NormTypes. + +@param src1 first input array. +@param src2 second input array of the same size and the same type as src1. +@param normType type of the norm (see #NormTypes). +@param mask optional operation mask; it must have the same size as src1 and +CV_8UC1 type. +*/ +CV_EXPORTS_W double norm(InputArray src1, InputArray src2, + int normType = NORM_L2, InputArray mask = noArray()); +/** @overload +@param src first input array. +@param normType type of the norm (see #NormTypes). +*/ +CV_EXPORTS double norm(const SparseMat &src, int normType); + +/** @brief Computes the Peak Signal-to-Noise Ratio (PSNR) image quality metric. + +This function calculates the Peak Signal-to-Noise Ratio (PSNR) image quality +metric in decibels (dB), between two input arrays src1 and src2. The arrays must +have the same type. + +The PSNR is calculated as follows: + +\f[ +\texttt{PSNR} = 10 \cdot \log_{10}{\left( \frac{R^2}{MSE} \right) } +\f] + +where R is the maximum integer value of depth (e.g. 255 in the case of CV_8U +data) and MSE is the mean squared error between the two arrays. + +@param src1 first input array. +@param src2 second input array of the same size as src1. +@param R the maximum pixel value (255 by default) + + */ +CV_EXPORTS_W double PSNR(InputArray src1, InputArray src2, double R = 255.); + +/** @brief naive nearest neighbor finder + +see http://en.wikipedia.org/wiki/Nearest_neighbor_search +@todo document + */ +CV_EXPORTS_W void batchDistance(InputArray src1, InputArray src2, + OutputArray dist, int dtype, OutputArray nidx, + int normType = NORM_L2, int K = 0, + InputArray mask = noArray(), int update = 0, + bool crosscheck = false); + +/** @brief Normalizes the norm or value range of an array. + +The function cv::normalize normalizes scale and shift the input array elements +so that +\f[\| \texttt{dst} \| _{L_p}= \texttt{alpha}\f] +(where p=Inf, 1 or 2) when normType=NORM_INF, NORM_L1, or NORM_L2, respectively; +or so that +\f[\min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= +\texttt{beta}\f] + +when normType=NORM_MINMAX (for dense arrays only). The optional mask specifies a +sub-array to be normalized. This means that the norm or min-n-max are calculated +over the sub-array, and then this sub-array is modified to be normalized. If you +want to only use the mask to calculate the norm or min-max but modify the whole +array, you can use norm and Mat::convertTo. + +In case of sparse matrices, only the non-zero values are analyzed and +transformed. Because of this, the range transformation for sparse matrices is +not allowed since it can shift the zero level. + +Possible usage with some positive example data: +@code{.cpp} + vector positiveData = { 2.0, 8.0, 10.0 }; + vector normalizedData_l1, normalizedData_l2, normalizedData_inf, +normalizedData_minmax; + + // Norm to probability (total count) + // sum(numbers) = 20.0 + // 2.0 0.1 (2.0/20.0) + // 8.0 0.4 (8.0/20.0) + // 10.0 0.5 (10.0/20.0) + normalize(positiveData, normalizedData_l1, 1.0, 0.0, NORM_L1); + + // Norm to unit vector: ||positiveData|| = 1.0 + // 2.0 0.15 + // 8.0 0.62 + // 10.0 0.77 + normalize(positiveData, normalizedData_l2, 1.0, 0.0, NORM_L2); + + // Norm to max element + // 2.0 0.2 (2.0/10.0) + // 8.0 0.8 (8.0/10.0) + // 10.0 1.0 (10.0/10.0) + normalize(positiveData, normalizedData_inf, 1.0, 0.0, NORM_INF); + + // Norm to range [0.0;1.0] + // 2.0 0.0 (shift to left border) + // 8.0 0.75 (6.0/8.0) + // 10.0 1.0 (shift to right border) + normalize(positiveData, normalizedData_minmax, 1.0, 0.0, NORM_MINMAX); +@endcode + +@param src input array. +@param dst output array of the same size as src . +@param alpha norm value to normalize to or the lower range boundary in case of +the range normalization. +@param beta upper range boundary in case of the range normalization; it is not +used for the norm normalization. +@param norm_type normalization type (see cv::NormTypes). +@param dtype when negative, the output array has the same type as src; +otherwise, it has the same number of channels as src and the depth +=CV_MAT_DEPTH(dtype). +@param mask optional operation mask. +@sa norm, Mat::convertTo, SparseMat::convertTo +*/ +CV_EXPORTS_W void normalize(InputArray src, InputOutputArray dst, + double alpha = 1, double beta = 0, + int norm_type = NORM_L2, int dtype = -1, + InputArray mask = noArray()); + +/** @overload +@param src input array. +@param dst output array of the same size as src . +@param alpha norm value to normalize to or the lower range boundary in case of +the range normalization. +@param normType normalization type (see cv::NormTypes). +*/ +CV_EXPORTS void normalize(const SparseMat &src, SparseMat &dst, double alpha, + int normType); + +/** @brief Finds the global minimum and maximum in an array. + +The function cv::minMaxLoc finds the minimum and maximum element values and +their positions. The extrema are searched across the whole array or, if mask is +not an empty array, in the specified array region. + +In C++, if the input is multi-channel, you should omit the minLoc, maxLoc, and +mask arguments (i.e. leave them as NULL, NULL, and noArray() respectively). +These arguments are not supported for multi-channel input arrays. If working +with multi-channel input and you need the minLoc, maxLoc, or mask arguments, +then use Mat::reshape first to reinterpret the array as single-channel. +Alternatively, you can extract the particular channel using either +extractImageCOI, mixChannels, or split. + +In Python, multi-channel input is not supported at all due to a limitation in +the binding generation process (there is no way to set minLoc and maxLoc to +NULL). A workaround is to operate on each channel individually or to use NumPy +to achieve the same functionality. + +@param src input single-channel array. +@param minVal pointer to the returned minimum value; NULL is used if not +required. +@param maxVal pointer to the returned maximum value; NULL is used if not +required. +@param minLoc pointer to the returned minimum location (in 2D case); NULL is +used if not required. +@param maxLoc pointer to the returned maximum location (in 2D case); NULL is +used if not required. +@param mask optional mask used to select a sub-array. +@sa max, min, reduceArgMin, reduceArgMax, compare, inRange, extractImageCOI, +mixChannels, split, Mat::reshape +*/ +CV_EXPORTS_W void minMaxLoc(InputArray src, CV_OUT double *minVal, + CV_OUT double *maxVal = 0, CV_OUT Point *minLoc = 0, + CV_OUT Point *maxLoc = 0, + InputArray mask = noArray()); + +/** + * @brief Finds indices of min elements along provided axis + * + * @note + * - If input or output array is not continuous, this function will create + * an internal copy. + * - NaN handling is left unspecified, see patchNaNs(). + * - The returned index is always in bounds of input matrix. + * + * @param src input single-channel array. + * @param dst output array of type CV_32SC1 with the same dimensionality as src, + * except for axis being reduced - it should be set to 1. + * @param lastIndex whether to get the index of first or last occurrence of min. + * @param axis axis to reduce along. + * @sa reduceArgMax, minMaxLoc, min, max, compare, reduce + */ +CV_EXPORTS_W void reduceArgMin(InputArray src, OutputArray dst, int axis, + bool lastIndex = false); + +/** + * @brief Finds indices of max elements along provided axis + * + * @note + * - If input or output array is not continuous, this function will create + * an internal copy. + * - NaN handling is left unspecified, see patchNaNs(). + * - The returned index is always in bounds of input matrix. + * + * @param src input single-channel array. + * @param dst output array of type CV_32SC1 with the same dimensionality as src, + * except for axis being reduced - it should be set to 1. + * @param lastIndex whether to get the index of first or last occurrence of max. + * @param axis axis to reduce along. + * @sa reduceArgMin, minMaxLoc, min, max, compare, reduce + */ +CV_EXPORTS_W void reduceArgMax(InputArray src, OutputArray dst, int axis, + bool lastIndex = false); + +/** @brief Finds the global minimum and maximum in an array + +The function cv::minMaxIdx finds the minimum and maximum element values and +their positions. The extremums are searched across the whole array or, if mask +is not an empty array, in the specified array region. In case of a sparse +matrix, the minimum is found among non-zero elements only. Multi-channel input +is supported without mask and extremums indexes (should be nullptr). +@note When minIdx is not NULL, it must have at least 2 elements (as well as +maxIdx), even if src is a single-row or single-column matrix. In OpenCV +(following MATLAB) each array has at least 2 dimensions, i.e. single-column +matrix is Mx1 matrix (and therefore minIdx/maxIdx will be (i1,0)/(i2,0)) and +single-row matrix is 1xN matrix (and therefore minIdx/maxIdx will be +(0,j1)/(0,j2)). +@param src input single-channel array. +@param minVal pointer to the returned minimum value; NULL is used if not +required. +@param maxVal pointer to the returned maximum value; NULL is used if not +required. +@param minIdx pointer to the returned minimum location (in nD case); NULL is +used if not required; Otherwise, it must point to an array of src.dims elements, +the coordinates of the minimum element in each dimension are stored there +sequentially. +@param maxIdx pointer to the returned maximum location (in nD case). NULL is +used if not required. +@param mask specified array region +*/ +CV_EXPORTS void minMaxIdx(InputArray src, double *minVal, double *maxVal = 0, + int *minIdx = 0, int *maxIdx = 0, + InputArray mask = noArray()); + +/** @overload +@param a input single-channel array. +@param minVal pointer to the returned minimum value; NULL is used if not +required. +@param maxVal pointer to the returned maximum value; NULL is used if not +required. +@param minIdx pointer to the returned minimum location (in nD case); NULL is +used if not required; Otherwise, it must point to an array of src.dims elements, +the coordinates of the minimum element in each dimension are stored there +sequentially. +@param maxIdx pointer to the returned maximum location (in nD case). NULL is +used if not required. +*/ +CV_EXPORTS void minMaxLoc(const SparseMat &a, double *minVal, double *maxVal, + int *minIdx = 0, int *maxIdx = 0); + +/** @brief Reduces a matrix to a vector. + +The function #reduce reduces the matrix to a vector by treating the matrix +rows/columns as a set of 1D vectors and performing the specified operation on +the vectors until a single row/column is obtained. For example, the function can +be used to compute horizontal and vertical projections of a raster image. In +case of #REDUCE_MAX and #REDUCE_MIN, the output image should have the same type +as the source one. In case of #REDUCE_SUM, #REDUCE_SUM2 and #REDUCE_AVG, the +output may have a larger element bit-depth to preserve accuracy. And +multi-channel arrays are also supported in these two reduction modes. + +The following code demonstrates its usage for a single channel matrix. +@snippet snippets/core_reduce.cpp example + +And the following code demonstrates its usage for a two-channel matrix. +@snippet snippets/core_reduce.cpp example2 + +@param src input 2D matrix. +@param dst output vector. Its size and type is defined by dim and dtype +parameters. +@param dim dimension index along which the matrix is reduced. 0 means that the +matrix is reduced to a single row. 1 means that the matrix is reduced to a +single column. +@param rtype reduction operation that could be one of #ReduceTypes +@param dtype when negative, the output vector will have the same type as the +input matrix, otherwise, its type will be CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), +src.channels()). +@sa repeat, reduceArgMin, reduceArgMax +*/ +CV_EXPORTS_W void reduce(InputArray src, OutputArray dst, int dim, int rtype, + int dtype = -1); + +/** @brief Creates one multi-channel array out of several single-channel ones. + +The function cv::merge merges several arrays to make a single multi-channel +array. That is, each element of the output array will be a concatenation of the +elements of the input arrays, where elements of i-th input array are treated as +mv[i].channels()-element vectors. + +The function cv::split does the reverse operation. If you need to shuffle +channels in some other advanced way, use cv::mixChannels. + +The following example shows how to merge 3 single channel matrices into a single +3-channel matrix. +@snippet snippets/core_merge.cpp example + +@param mv input array of matrices to be merged; all the matrices in mv must have +the same size and the same depth. +@param count number of input matrices when mv is a plain C array; it must be +greater than zero. +@param dst output array of the same size and the same depth as mv[0]; The number +of channels will be equal to the parameter count. +@sa mixChannels, split, Mat::reshape +*/ +CV_EXPORTS void merge(const Mat *mv, size_t count, OutputArray dst); + +/** @overload +@param mv input vector of matrices to be merged; all the matrices in mv must +have the same size and the same depth. +@param dst output array of the same size and the same depth as mv[0]; The number +of channels will be the total number of channels in the matrix array. + */ +CV_EXPORTS_W void merge(InputArrayOfArrays mv, OutputArray dst); + +/** @brief Divides a multi-channel array into several single-channel arrays. + +The function cv::split splits a multi-channel array into separate single-channel +arrays: +\f[\texttt{mv} [c](I) = \texttt{src} (I)_c\f] +If you need to extract a single channel or do some other sophisticated channel +permutation, use mixChannels. + +The following example demonstrates how to split a 3-channel matrix into 3 single +channel matrices. +@snippet snippets/core_split.cpp example + +@param src input multi-channel array. +@param mvbegin output array; the number of arrays must match src.channels(); the +arrays themselves are reallocated, if needed. +@sa merge, mixChannels, cvtColor +*/ +CV_EXPORTS void split(const Mat &src, Mat *mvbegin); + +/** @overload +@param m input multi-channel array. +@param mv output vector of arrays; the arrays themselves are reallocated, if +needed. +*/ +CV_EXPORTS_W void split(InputArray m, OutputArrayOfArrays mv); + +/** @brief Copies specified channels from input arrays to the specified channels +of output arrays. + +The function cv::mixChannels provides an advanced mechanism for shuffling image +channels. + +cv::split,cv::merge,cv::extractChannel,cv::insertChannel and some forms of +cv::cvtColor are partial cases of cv::mixChannels. + +In the example below, the code splits a 4-channel BGRA image into a 3-channel +BGR (with B and R channels swapped) and a separate alpha-channel image: +@code{.cpp} + Mat bgra( 100, 100, CV_8UC4, Scalar(255,0,0,255) ); + Mat bgr( bgra.rows, bgra.cols, CV_8UC3 ); + Mat alpha( bgra.rows, bgra.cols, CV_8UC1 ); + + // forming an array of matrices is a quite efficient operation, + // because the matrix data is not copied, only the headers + Mat out[] = { bgr, alpha }; + // bgra[0] -> bgr[2], bgra[1] -> bgr[1], + // bgra[2] -> bgr[0], bgra[3] -> alpha[0] + int from_to[] = { 0,2, 1,1, 2,0, 3,3 }; + mixChannels( &bgra, 1, out, 2, from_to, 4 ); +@endcode +@note Unlike many other new-style C++ functions in OpenCV (see the introduction +section and Mat::create ), cv::mixChannels requires the output arrays to be +pre-allocated before calling the function. +@param src input array or vector of matrices; all of the matrices must have the +same size and the same depth. +@param nsrcs number of matrices in `src`. +@param dst output array or vector of matrices; all the matrices **must be +allocated**; their size and depth must be the same as in `src[0]`. +@param ndsts number of matrices in `dst`. +@param fromTo array of index pairs specifying which channels are copied and +where; fromTo[k\*2] is a 0-based index of the input channel in src, +fromTo[k\*2+1] is an index of the output channel in dst; the continuous channel +numbering is used: the first input image channels are indexed from 0 to +src[0].channels()-1, the second input image channels are indexed from +src[0].channels() to src[0].channels() + src[1].channels()-1, and so on, the +same scheme is used for the output image channels; as a special case, when +fromTo[k\*2] is negative, the corresponding output channel is filled with zero . +@param npairs number of index pairs in `fromTo`. +@sa split, merge, extractChannel, insertChannel, cvtColor +*/ +CV_EXPORTS void mixChannels(const Mat *src, size_t nsrcs, Mat *dst, + size_t ndsts, const int *fromTo, size_t npairs); + +/** @overload +@param src input array or vector of matrices; all of the matrices must have the +same size and the same depth. +@param dst output array or vector of matrices; all the matrices **must be +allocated**; their size and depth must be the same as in src[0]. +@param fromTo array of index pairs specifying which channels are copied and +where; fromTo[k\*2] is a 0-based index of the input channel in src, +fromTo[k\*2+1] is an index of the output channel in dst; the continuous channel +numbering is used: the first input image channels are indexed from 0 to +src[0].channels()-1, the second input image channels are indexed from +src[0].channels() to src[0].channels() + src[1].channels()-1, and so on, the +same scheme is used for the output image channels; as a special case, when +fromTo[k\*2] is negative, the corresponding output channel is filled with zero . +@param npairs number of index pairs in fromTo. +*/ +CV_EXPORTS void mixChannels(InputArrayOfArrays src, + InputOutputArrayOfArrays dst, const int *fromTo, + size_t npairs); + +/** @overload +@param src input array or vector of matrices; all of the matrices must have the +same size and the same depth. +@param dst output array or vector of matrices; all the matrices **must be +allocated**; their size and depth must be the same as in src[0]. +@param fromTo array of index pairs specifying which channels are copied and +where; fromTo[k\*2] is a 0-based index of the input channel in src, +fromTo[k\*2+1] is an index of the output channel in dst; the continuous channel +numbering is used: the first input image channels are indexed from 0 to +src[0].channels()-1, the second input image channels are indexed from +src[0].channels() to src[0].channels() + src[1].channels()-1, and so on, the +same scheme is used for the output image channels; as a special case, when +fromTo[k\*2] is negative, the corresponding output channel is filled with zero . +*/ +CV_EXPORTS_W void mixChannels(InputArrayOfArrays src, + InputOutputArrayOfArrays dst, + const std::vector &fromTo); + +/** @brief Extracts a single channel from src (coi is 0-based index) +@param src input array +@param dst output array +@param coi index of channel to extract +@sa mixChannels, split +*/ +CV_EXPORTS_W void extractChannel(InputArray src, OutputArray dst, int coi); + +/** @brief Inserts a single channel to dst (coi is 0-based index) +@param src input array +@param dst output array +@param coi index of channel for insertion +@sa mixChannels, merge +*/ +CV_EXPORTS_W void insertChannel(InputArray src, InputOutputArray dst, int coi); + +/** @brief Flips a 2D array around vertical, horizontal, or both axes. + +The function cv::flip flips the array in one of three different ways (row +and column indices are 0-based): +\f[\texttt{dst} _{ij} = +\left\{ +\begin{array}{l l} +\texttt{src} _{\texttt{src.rows}-i-1,j} & if\; \texttt{flipCode} = 0 \\ +\texttt{src} _{i, \texttt{src.cols} -j-1} & if\; \texttt{flipCode} > 0 \\ +\texttt{src} _{ \texttt{src.rows} -i-1, \texttt{src.cols} -j-1} & if\; +\texttt{flipCode} < 0 \\ +\end{array} +\right.\f] +The example scenarios of using the function are the following: +* Vertical flipping of the image (flipCode == 0) to switch between + top-left and bottom-left image origin. This is a typical operation + in video processing on Microsoft Windows\* OS. +* Horizontal flipping of the image with the subsequent horizontal + shift and absolute difference calculation to check for a + vertical-axis symmetry (flipCode \> 0). +* Simultaneous horizontal and vertical flipping of the image with + the subsequent shift and absolute difference calculation to check + for a central symmetry (flipCode \< 0). +* Reversing the order of point arrays (flipCode \> 0 or + flipCode == 0). +@param src input array. +@param dst output array of the same size and type as src. +@param flipCode a flag to specify how to flip the array; 0 means +flipping around the x-axis and positive value (for example, 1) means +flipping around y-axis. Negative value (for example, -1) means flipping +around both axes. +@sa transpose, repeat, completeSymm +*/ +CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode); + +/** @brief Flips a n-dimensional at given axis + * @param src input array + * @param dst output array that has the same shape of src + * @param axis axis that performs a flip on. 0 <= axis < src.dims. + */ +CV_EXPORTS_W void flipND(InputArray src, OutputArray dst, int axis); + +/** @brief Broadcast the given Mat to the given shape. + * @param src input array + * @param shape target shape. Should be a list of CV_32S numbers. Note that + * negative values are not supported. + * @param dst output array that has the given shape + */ +CV_EXPORTS_W void broadcast(InputArray src, InputArray shape, OutputArray dst); + +enum RotateFlags { + ROTATE_90_CLOCKWISE = 0, //!< Rotate 90 degrees clockwise + ROTATE_180 = 1, //!< Rotate 180 degrees clockwise + ROTATE_90_COUNTERCLOCKWISE = 2, //!< Rotate 270 degrees clockwise +}; +/** @brief Rotates a 2D array in multiples of 90 degrees. +The function cv::rotate rotates the array in one of three different ways: +* Rotate by 90 degrees clockwise (rotateCode = ROTATE_90_CLOCKWISE). +* Rotate by 180 degrees clockwise (rotateCode = ROTATE_180). +* Rotate by 270 degrees clockwise (rotateCode = ROTATE_90_COUNTERCLOCKWISE). +@param src input array. +@param dst output array of the same type as src. The size is the same with +ROTATE_180, and the rows and cols are switched for ROTATE_90_CLOCKWISE and +ROTATE_90_COUNTERCLOCKWISE. +@param rotateCode an enum to specify how to rotate the array; see the enum +#RotateFlags +@sa transpose, repeat, completeSymm, flip, RotateFlags +*/ +CV_EXPORTS_W void rotate(InputArray src, OutputArray dst, int rotateCode); + +/** @brief Fills the output array with repeated copies of the input array. + +The function cv::repeat duplicates the input array one or more times along each +of the two axes: +\f[\texttt{dst} _{ij}= \texttt{src} _{i\mod src.rows, \; j\mod src.cols }\f] +The second variant of the function is more convenient to use with @ref +MatrixExpressions. +@param src input array to replicate. +@param ny Flag to specify how many times the `src` is repeated along the +vertical axis. +@param nx Flag to specify how many times the `src` is repeated along the +horizontal axis. +@param dst output array of the same type as `src`. +@sa cv::reduce +*/ +CV_EXPORTS_W void repeat(InputArray src, int ny, int nx, OutputArray dst); + +/** @overload +@param src input array to replicate. +@param ny Flag to specify how many times the `src` is repeated along the +vertical axis. +@param nx Flag to specify how many times the `src` is repeated along the +horizontal axis. + */ +CV_EXPORTS Mat repeat(const Mat &src, int ny, int nx); + +/** @brief Applies horizontal concatenation to given matrices. + +The function horizontally concatenates two or more cv::Mat matrices (with the +same number of rows). +@code{.cpp} + cv::Mat matArray[] = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)), + cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)), + cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),}; + + cv::Mat out; + cv::hconcat( matArray, 3, out ); + //out: + //[1, 2, 3; + // 1, 2, 3; + // 1, 2, 3; + // 1, 2, 3] +@endcode +@param src input array or vector of matrices. all of the matrices must have the +same number of rows and the same depth. +@param nsrc number of matrices in src. +@param dst output array. It has the same number of rows and depth as the src, +and the sum of cols of the src. +@sa cv::vconcat(const Mat*, size_t, OutputArray), @sa +cv::vconcat(InputArrayOfArrays, OutputArray) and @sa cv::vconcat(InputArray, +InputArray, OutputArray) +*/ +CV_EXPORTS void hconcat(const Mat *src, size_t nsrc, OutputArray dst); +/** @overload + @code{.cpp} + cv::Mat_ A = (cv::Mat_(3, 2) << 1, 4, + 2, 5, + 3, 6); + cv::Mat_ B = (cv::Mat_(3, 2) << 7, 10, + 8, 11, + 9, 12); + + cv::Mat C; + cv::hconcat(A, B, C); + //C: + //[1, 4, 7, 10; + // 2, 5, 8, 11; + // 3, 6, 9, 12] + @endcode + @param src1 first input array to be considered for horizontal concatenation. + @param src2 second input array to be considered for horizontal concatenation. + @param dst output array. It has the same number of rows and depth as the src1 + and src2, and the sum of cols of the src1 and src2. + */ +CV_EXPORTS void hconcat(InputArray src1, InputArray src2, OutputArray dst); +/** @overload + @code{.cpp} + std::vector matrices = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)), + cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)), + cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),}; + + cv::Mat out; + cv::hconcat( matrices, out ); + //out: + //[1, 2, 3; + // 1, 2, 3; + // 1, 2, 3; + // 1, 2, 3] + @endcode + @param src input array or vector of matrices. all of the matrices must have the +same number of rows and the same depth. + @param dst output array. It has the same number of rows and depth as the src, +and the sum of cols of the src. same depth. + */ +CV_EXPORTS_W void hconcat(InputArrayOfArrays src, OutputArray dst); + +/** @brief Applies vertical concatenation to given matrices. + +The function vertically concatenates two or more cv::Mat matrices (with the same +number of cols). +@code{.cpp} + cv::Mat matArray[] = { cv::Mat(1, 4, CV_8UC1, cv::Scalar(1)), + cv::Mat(1, 4, CV_8UC1, cv::Scalar(2)), + cv::Mat(1, 4, CV_8UC1, cv::Scalar(3)),}; + + cv::Mat out; + cv::vconcat( matArray, 3, out ); + //out: + //[1, 1, 1, 1; + // 2, 2, 2, 2; + // 3, 3, 3, 3] +@endcode +@param src input array or vector of matrices. all of the matrices must have the +same number of cols and the same depth. +@param nsrc number of matrices in src. +@param dst output array. It has the same number of cols and depth as the src, +and the sum of rows of the src. +@sa cv::hconcat(const Mat*, size_t, OutputArray), @sa +cv::hconcat(InputArrayOfArrays, OutputArray) and @sa cv::hconcat(InputArray, +InputArray, OutputArray) +*/ +CV_EXPORTS void vconcat(const Mat *src, size_t nsrc, OutputArray dst); +/** @overload + @code{.cpp} + cv::Mat_ A = (cv::Mat_(3, 2) << 1, 7, + 2, 8, + 3, 9); + cv::Mat_ B = (cv::Mat_(3, 2) << 4, 10, + 5, 11, + 6, 12); + + cv::Mat C; + cv::vconcat(A, B, C); + //C: + //[1, 7; + // 2, 8; + // 3, 9; + // 4, 10; + // 5, 11; + // 6, 12] + @endcode + @param src1 first input array to be considered for vertical concatenation. + @param src2 second input array to be considered for vertical concatenation. + @param dst output array. It has the same number of cols and depth as the src1 + and src2, and the sum of rows of the src1 and src2. + */ +CV_EXPORTS void vconcat(InputArray src1, InputArray src2, OutputArray dst); +/** @overload + @code{.cpp} + std::vector matrices = { cv::Mat(1, 4, CV_8UC1, cv::Scalar(1)), + cv::Mat(1, 4, CV_8UC1, cv::Scalar(2)), + cv::Mat(1, 4, CV_8UC1, cv::Scalar(3)),}; + + cv::Mat out; + cv::vconcat( matrices, out ); + //out: + //[1, 1, 1, 1; + // 2, 2, 2, 2; + // 3, 3, 3, 3] + @endcode + @param src input array or vector of matrices. all of the matrices must have the +same number of cols and the same depth + @param dst output array. It has the same number of cols and depth as the src, +and the sum of rows of the src. same depth. + */ +CV_EXPORTS_W void vconcat(InputArrayOfArrays src, OutputArray dst); + +/** @brief computes bitwise conjunction of the two arrays (dst = src1 & src2) +Calculates the per-element bit-wise conjunction of two arrays or an +array and a scalar. + +The function cv::bitwise_and calculates the per-element bit-wise logical +conjunction for: +* Two arrays when src1 and src2 have the same size: + \f[\texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} (I) \quad +\texttt{if mask} (I) \ne0\f] +* An array and a scalar when src2 is constructed from Scalar or has + the same number of elements as `src1.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} \quad +\texttt{if mask} (I) \ne0\f] +* A scalar and an array when src1 is constructed from Scalar or has + the same number of elements as `src2.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} \wedge \texttt{src2} (I) \quad +\texttt{if mask} (I) \ne0\f] In case of floating-point arrays, their +machine-specific bit representations (usually IEEE754-compliant) are used for +the operation. In case of multi-channel arrays, each channel is processed +independently. In the second and third cases above, the scalar is first +converted to the array type. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and type as the input +arrays. +@param mask optional operation mask, 8-bit single channel array, that +specifies elements of the output array to be changed. +*/ +CV_EXPORTS_W void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask = noArray()); + +/** @brief Calculates the per-element bit-wise disjunction of two arrays or an +array and a scalar. + +The function cv::bitwise_or calculates the per-element bit-wise logical +disjunction for: +* Two arrays when src1 and src2 have the same size: + \f[\texttt{dst} (I) = \texttt{src1} (I) \vee \texttt{src2} (I) \quad +\texttt{if mask} (I) \ne0\f] +* An array and a scalar when src2 is constructed from Scalar or has + the same number of elements as `src1.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} (I) \vee \texttt{src2} \quad +\texttt{if mask} (I) \ne0\f] +* A scalar and an array when src1 is constructed from Scalar or has + the same number of elements as `src2.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} \vee \texttt{src2} (I) \quad +\texttt{if mask} (I) \ne0\f] In case of floating-point arrays, their +machine-specific bit representations (usually IEEE754-compliant) are used for +the operation. In case of multi-channel arrays, each channel is processed +independently. In the second and third cases above, the scalar is first +converted to the array type. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and type as the input +arrays. +@param mask optional operation mask, 8-bit single channel array, that +specifies elements of the output array to be changed. +*/ +CV_EXPORTS_W void bitwise_or(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask = noArray()); + +/** @brief Calculates the per-element bit-wise "exclusive or" operation on two +arrays or an array and a scalar. + +The function cv::bitwise_xor calculates the per-element bit-wise logical +"exclusive-or" operation for: +* Two arrays when src1 and src2 have the same size: + \f[\texttt{dst} (I) = \texttt{src1} (I) \oplus \texttt{src2} (I) \quad +\texttt{if mask} (I) \ne0\f] +* An array and a scalar when src2 is constructed from Scalar or has + the same number of elements as `src1.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} (I) \oplus \texttt{src2} \quad +\texttt{if mask} (I) \ne0\f] +* A scalar and an array when src1 is constructed from Scalar or has + the same number of elements as `src2.channels()`: + \f[\texttt{dst} (I) = \texttt{src1} \oplus \texttt{src2} (I) \quad +\texttt{if mask} (I) \ne0\f] In case of floating-point arrays, their +machine-specific bit representations (usually IEEE754-compliant) are used for +the operation. In case of multi-channel arrays, each channel is processed +independently. In the 2nd and 3rd cases above, the scalar is first +converted to the array type. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and type as the input +arrays. +@param mask optional operation mask, 8-bit single channel array, that +specifies elements of the output array to be changed. +*/ +CV_EXPORTS_W void bitwise_xor(InputArray src1, InputArray src2, OutputArray dst, + InputArray mask = noArray()); + +/** @brief Inverts every bit of an array. + +The function cv::bitwise_not calculates per-element bit-wise inversion of the +input array: +\f[\texttt{dst} (I) = \neg \texttt{src} (I)\f] +In case of a floating-point input array, its machine-specific bit +representation (usually IEEE754-compliant) is used for the operation. In +case of multi-channel arrays, each channel is processed independently. +@param src input array. +@param dst output array that has the same size and type as the input +array. +@param mask optional operation mask, 8-bit single channel array, that +specifies elements of the output array to be changed. +*/ +CV_EXPORTS_W void bitwise_not(InputArray src, OutputArray dst, + InputArray mask = noArray()); + +/** @brief Calculates the per-element absolute difference between two arrays or +between an array and a scalar. + +The function cv::absdiff calculates: +* Absolute difference between two arrays when they have the same + size and type: + \f[\texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - +\texttt{src2}(I)|)\f] +* Absolute difference between an array and a scalar when the second + array is constructed from Scalar or has as many elements as the + number of channels in `src1`: + \f[\texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - \texttt{src2} +|)\f] +* Absolute difference between a scalar and an array when the first + array is constructed from Scalar or has as many elements as the + number of channels in `src2`: + \f[\texttt{dst}(I) = \texttt{saturate} (| \texttt{src1} - \texttt{src2}(I) +|)\f] where I is a multi-dimensional index of array elements. In case of + multi-channel arrays, each channel is processed independently. +@note Saturation is not applied when the arrays have the depth CV_32S. +You may even get a negative value in the case of overflow. +@note (Python) Be careful to difference behaviour between src1/src2 are single +number and they are tuple/array. `absdiff(src,X)` means +`absdiff(src,(X,X,X,X))`. `absdiff(src,(X,))` means `absdiff(src,(X,0,0,0))`. +@param src1 first input array or a scalar. +@param src2 second input array or a scalar. +@param dst output array that has the same size and type as input arrays. +@sa cv::abs(const Mat&) +*/ +CV_EXPORTS_W void absdiff(InputArray src1, InputArray src2, OutputArray dst); + +/** @brief This is an overloaded member function, provided for convenience +(python) Copies the matrix to another one. When the operation mask is specified, +if the Mat::create call shown above reallocates the matrix, the newly allocated +matrix is initialized with all zeros before copying the data. +@param src source matrix. +@param dst Destination matrix. If it does not have a proper size or type before +the operation, it is reallocated. +@param mask Operation mask of the same size as \*this. Its non-zero elements +indicate which matrix elements need to be copied. The mask has to be of type +CV_8U and can have 1 or multiple channels. +*/ + +void CV_EXPORTS_W copyTo(InputArray src, OutputArray dst, InputArray mask); +/** @brief Checks if array elements lie between the elements of two other +arrays. + +The function checks the range as follows: +- For every element of a single-channel input array: + \f[\texttt{dst} (I)= \texttt{lowerb} (I)_0 \leq \texttt{src} (I)_0 \leq +\texttt{upperb} (I)_0\f] +- For two-channel arrays: + \f[\texttt{dst} (I)= \texttt{lowerb} (I)_0 \leq \texttt{src} (I)_0 \leq +\texttt{upperb} (I)_0 \land \texttt{lowerb} (I)_1 \leq \texttt{src} (I)_1 \leq +\texttt{upperb} (I)_1\f] +- and so forth. + +That is, dst (I) is set to 255 (all 1 -bits) if src (I) is within the +specified 1D, 2D, 3D, ... box and 0 otherwise. + +When the lower and/or upper boundary parameters are scalars, the indexes +(I) at lowerb and upperb in the above formulas should be omitted. +@param src first input array. +@param lowerb inclusive lower boundary array or a scalar. +@param upperb inclusive upper boundary array or a scalar. +@param dst output array of the same size as src and CV_8U type. +*/ +CV_EXPORTS_W void inRange(InputArray src, InputArray lowerb, InputArray upperb, + OutputArray dst); + +/** @brief Performs the per-element comparison of two arrays or an array and +scalar value. + +The function compares: +* Elements of two arrays when src1 and src2 have the same size: + \f[\texttt{dst} (I) = \texttt{src1} (I) \,\texttt{cmpop}\, \texttt{src2} +(I)\f] +* Elements of src1 with a scalar src2 when src2 is constructed from + Scalar or has a single element: + \f[\texttt{dst} (I) = \texttt{src1}(I) \,\texttt{cmpop}\, \texttt{src2}\f] +* src1 with elements of src2 when src1 is constructed from Scalar or + has a single element: + \f[\texttt{dst} (I) = \texttt{src1} \,\texttt{cmpop}\, \texttt{src2} +(I)\f] When the comparison result is true, the corresponding element of output +array is set to 255. The comparison operations can be replaced with the +equivalent matrix expressions: +@code{.cpp} + Mat dst1 = src1 >= src2; + Mat dst2 = src1 < 8; + ... +@endcode +@param src1 first input array or a scalar; when it is an array, it must have a +single channel. +@param src2 second input array or a scalar; when it is an array, it must have a +single channel. +@param dst output array of type ref CV_8U that has the same size and the same +number of channels as the input arrays. +@param cmpop a flag, that specifies correspondence between the arrays +(cv::CmpTypes) +@sa checkRange, min, max, threshold +*/ +CV_EXPORTS_W void compare(InputArray src1, InputArray src2, OutputArray dst, + int cmpop); + +/** @brief Calculates per-element minimum of two arrays or an array and a +scalar. + +The function cv::min calculates the per-element minimum of two arrays: +\f[\texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{src2} (I))\f] +or array and a scalar: +\f[\texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{value} )\f] +@param src1 first input array. +@param src2 second input array of the same size and type as src1. +@param dst output array of the same size and type as src1. +@sa max, compare, inRange, minMaxLoc +*/ +CV_EXPORTS_W void min(InputArray src1, InputArray src2, OutputArray dst); +/** @overload +needed to avoid conflicts with const _Tp& std::min(const _Tp&, const _Tp&, +_Compare) +*/ +CV_EXPORTS void min(const Mat &src1, const Mat &src2, Mat &dst); + +/** @brief Calculates per-element maximum of two arrays or an array and a +scalar. + +The function cv::max calculates the per-element maximum of two arrays: +\f[\texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{src2} (I))\f] +or array and a scalar: +\f[\texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{value} )\f] +@param src1 first input array. +@param src2 second input array of the same size and type as src1 . +@param dst output array of the same size and type as src1. +@sa min, compare, inRange, minMaxLoc, @ref MatrixExpressions +*/ +CV_EXPORTS_W void max(InputArray src1, InputArray src2, OutputArray dst); +/** @overload +needed to avoid conflicts with const _Tp& std::min(const _Tp&, const _Tp&, +_Compare) +*/ +CV_EXPORTS void max(const Mat &src1, const Mat &src2, Mat &dst); + +/** @brief Calculates a square root of array elements. + +The function cv::sqrt calculates a square root of each input array element. +In case of multi-channel arrays, each channel is processed +independently. The accuracy is approximately the same as of the built-in +std::sqrt . +@param src input floating-point array. +@param dst output array of the same size and type as src. +*/ +CV_EXPORTS_W void sqrt(InputArray src, OutputArray dst); + +/** @brief Raises every array element to a power. + +The function cv::pow raises every element of the input array to power : +\f[\texttt{dst} (I) = \fork{\texttt{src}(I)^{power}}{if \(\texttt{power}\) is +integer}{|\texttt{src}(I)|^{power}}{otherwise}\f] + +So, for a non-integer power exponent, the absolute values of input array +elements are used. However, it is possible to get true values for +negative values using some extra operations. In the example below, +computing the 5th root of array src shows: +@code{.cpp} + Mat mask = src < 0; + pow(src, 1./5, dst); + subtract(Scalar::all(0), dst, dst, mask); +@endcode +For some values of power, such as integer values, 0.5 and -0.5, +specialized faster algorithms are used. + +Special values (NaN, Inf) are not handled. +@param src input array. +@param power exponent of power. +@param dst output array of the same size and type as src. +@sa sqrt, exp, log, cartToPolar, polarToCart +*/ +CV_EXPORTS_W void pow(InputArray src, double power, OutputArray dst); + +/** @brief Calculates the exponent of every array element. + +The function cv::exp calculates the exponent of every element of the input +array: +\f[\texttt{dst} [I] = e^{ src(I) }\f] + +The maximum relative error is about 7e-6 for single-precision input and +less than 1e-10 for double-precision input. Currently, the function +converts denormalized values to zeros on output. Special values (NaN, +Inf) are not handled. +@param src input array. +@param dst output array of the same size and type as src. +@sa log, cartToPolar, polarToCart, phase, pow, sqrt, magnitude +*/ +CV_EXPORTS_W void exp(InputArray src, OutputArray dst); + +/** @brief Calculates the natural logarithm of every array element. + +The function cv::log calculates the natural logarithm of every element of the +input array: +\f[\texttt{dst} (I) = \log (\texttt{src}(I)) \f] + +Output on zero, negative and special (NaN, Inf) values is undefined. + +@param src input array. +@param dst output array of the same size and type as src . +@sa exp, cartToPolar, polarToCart, phase, pow, sqrt, magnitude +*/ +CV_EXPORTS_W void log(InputArray src, OutputArray dst); + +/** @brief Calculates x and y coordinates of 2D vectors from their magnitude and +angle. + +The function cv::polarToCart calculates the Cartesian coordinates of each 2D +vector represented by the corresponding elements of magnitude and angle: +\f[\begin{array}{l} \texttt{x} (I) = \texttt{magnitude} (I) \cos ( +\texttt{angle} (I)) \\ \texttt{y} (I) = \texttt{magnitude} (I) \sin ( +\texttt{angle} (I)) \\ \end{array}\f] + +The relative accuracy of the estimated coordinates is about 1e-6. +@param magnitude input floating-point array of magnitudes of 2D vectors; +it can be an empty matrix (=Mat()), in this case, the function assumes +that all the magnitudes are =1; if it is not empty, it must have the +same size and type as angle. +@param angle input floating-point array of angles of 2D vectors. +@param x output array of x-coordinates of 2D vectors; it has the same +size and type as angle. +@param y output array of y-coordinates of 2D vectors; it has the same +size and type as angle. +@param angleInDegrees when true, the input angles are measured in +degrees, otherwise, they are measured in radians. +@sa cartToPolar, magnitude, phase, exp, log, pow, sqrt +*/ +CV_EXPORTS_W void polarToCart(InputArray magnitude, InputArray angle, + OutputArray x, OutputArray y, + bool angleInDegrees = false); + +/** @brief Calculates the magnitude and angle of 2D vectors. + +The function cv::cartToPolar calculates either the magnitude, angle, or both +for every 2D vector (x(I),y(I)): +\f[\begin{array}{l} \texttt{magnitude} (I)= +\sqrt{\texttt{x}(I)^2+\texttt{y}(I)^2} , \\ \texttt{angle} (I)= \texttt{atan2} ( +\texttt{y} (I), \texttt{x} (I))[ \cdot180 / \pi ] \end{array}\f] + +The angles are calculated with accuracy about 0.3 degrees. For the point +(0,0), the angle is set to 0. +@param x array of x-coordinates; this must be a single-precision or +double-precision floating-point array. +@param y array of y-coordinates, that must have the same size and same type as +x. +@param magnitude output array of magnitudes of the same size and type as x. +@param angle output array of angles that has the same size and type as +x; the angles are measured in radians (from 0 to 2\*Pi) or in degrees (0 to 360 +degrees). +@param angleInDegrees a flag, indicating whether the angles are measured +in radians (which is by default), or in degrees. +@sa Sobel, Scharr +*/ +CV_EXPORTS_W void cartToPolar(InputArray x, InputArray y, OutputArray magnitude, + OutputArray angle, bool angleInDegrees = false); + +/** @brief Calculates the rotation angle of 2D vectors. + +The function cv::phase calculates the rotation angle of each 2D vector that +is formed from the corresponding elements of x and y : +\f[\texttt{angle} (I) = \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I))\f] + +The angle estimation accuracy is about 0.3 degrees. When x(I)=y(I)=0 , +the corresponding angle(I) is set to 0. +@param x input floating-point array of x-coordinates of 2D vectors. +@param y input array of y-coordinates of 2D vectors; it must have the +same size and the same type as x. +@param angle output array of vector angles; it has the same size and +same type as x . +@param angleInDegrees when true, the function calculates the angle in +degrees, otherwise, they are measured in radians. +*/ +CV_EXPORTS_W void phase(InputArray x, InputArray y, OutputArray angle, + bool angleInDegrees = false); + +/** @brief Calculates the magnitude of 2D vectors. + +The function cv::magnitude calculates the magnitude of 2D vectors formed +from the corresponding elements of x and y arrays: +\f[\texttt{dst} (I) = \sqrt{\texttt{x}(I)^2 + \texttt{y}(I)^2}\f] +@param x floating-point array of x-coordinates of the vectors. +@param y floating-point array of y-coordinates of the vectors; it must +have the same size as x. +@param magnitude output array of the same size and type as x. +@sa cartToPolar, polarToCart, phase, sqrt +*/ +CV_EXPORTS_W void magnitude(InputArray x, InputArray y, OutputArray magnitude); + +/** @brief Checks every element of an input array for invalid values. + +The function cv::checkRange checks that every array element is neither NaN nor +infinite. When minVal \> -DBL_MAX and maxVal \< DBL_MAX, the function also +checks that each value is between minVal and maxVal. In case of multi-channel +arrays, each channel is processed independently. If some values are out of +range, position of the first outlier is stored in pos (when pos != NULL). Then, +the function either returns false (when quiet=true) or throws an exception. +@param a input array. +@param quiet a flag, indicating whether the functions quietly return false when +the array elements are out of range or they throw an exception. +@param pos optional output parameter, when not NULL, must be a pointer to array +of src.dims elements. +@param minVal inclusive lower boundary of valid values range. +@param maxVal exclusive upper boundary of valid values range. +*/ +CV_EXPORTS_W bool checkRange(InputArray a, bool quiet = true, + CV_OUT Point *pos = 0, double minVal = -DBL_MAX, + double maxVal = DBL_MAX); + +/** @brief Replaces NaNs by given number +@param a input/output matrix (CV_32F type). +@param val value to convert the NaNs +*/ +CV_EXPORTS_W void patchNaNs(InputOutputArray a, double val = 0); + +/** @brief Performs generalized matrix multiplication. + +The function cv::gemm performs generalized matrix multiplication similar to the +gemm functions in BLAS level 3. For example, +`gemm(src1, src2, alpha, src3, beta, dst, GEMM_1_T + GEMM_3_T)` +corresponds to +\f[\texttt{dst} = \texttt{alpha} \cdot \texttt{src1} ^T \cdot \texttt{src2} + +\texttt{beta} \cdot \texttt{src3} ^T\f] + +In case of complex (two-channel) data, performed a complex matrix +multiplication. + +The function can be replaced with a matrix expression. For example, the +above call can be replaced with: +@code{.cpp} + dst = alpha*src1.t()*src2 + beta*src3.t(); +@endcode +@param src1 first multiplied input matrix that could be real(CV_32FC1, +CV_64FC1) or complex(CV_32FC2, CV_64FC2). +@param src2 second multiplied input matrix of the same type as src1. +@param alpha weight of the matrix product. +@param src3 third optional delta matrix added to the matrix product; it +should have the same type as src1 and src2. +@param beta weight of src3. +@param dst output matrix; it has the proper size and the same type as +input matrices. +@param flags operation flags (cv::GemmFlags) +@sa mulTransposed, transform +*/ +CV_EXPORTS_W void gemm(InputArray src1, InputArray src2, double alpha, + InputArray src3, double beta, OutputArray dst, + int flags = 0); + +/** @brief Calculates the product of a matrix and its transposition. + +The function cv::mulTransposed calculates the product of src and its +transposition: +\f[\texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} )^T ( +\texttt{src} - \texttt{delta} )\f] if aTa=true, and +\f[\texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} ) ( +\texttt{src} - \texttt{delta} )^T\f] otherwise. The function is used to +calculate the covariance matrix. With zero delta, it can be used as a faster +substitute for general matrix product A\*B when B=A' +@param src input single-channel matrix. Note that unlike gemm, the +function can multiply not only floating-point matrices. +@param dst output square matrix. +@param aTa Flag specifying the multiplication ordering. See the +description below. +@param delta Optional delta matrix subtracted from src before the +multiplication. When the matrix is empty ( delta=noArray() ), it is +assumed to be zero, that is, nothing is subtracted. If it has the same +size as src, it is simply subtracted. Otherwise, it is "repeated" (see +repeat ) to cover the full src and then subtracted. Type of the delta +matrix, when it is not empty, must be the same as the type of created +output matrix. See the dtype parameter description below. +@param scale Optional scale factor for the matrix product. +@param dtype Optional type of the output matrix. When it is negative, +the output matrix will have the same type as src . Otherwise, it will be +type=CV_MAT_DEPTH(dtype) that should be either CV_32F or CV_64F . +@sa calcCovarMatrix, gemm, repeat, reduce +*/ +CV_EXPORTS_W void mulTransposed(InputArray src, OutputArray dst, bool aTa, + InputArray delta = noArray(), double scale = 1, + int dtype = -1); + +/** @brief Transposes a matrix. + +The function cv::transpose transposes the matrix src : +\f[\texttt{dst} (i,j) = \texttt{src} (j,i)\f] +@note No complex conjugation is done in case of a complex matrix. It +should be done separately if needed. +@param src input array. +@param dst output array of the same type as src. +*/ +CV_EXPORTS_W void transpose(InputArray src, OutputArray dst); + +/** @brief Transpose for n-dimensional matrices. + * + * @note Input should be continuous single-channel matrix. + * @param src input array. + * @param order a permutation of [0,1,..,N-1] where N is the number of axes of + * src. The i'th axis of dst will correspond to the axis numbered order[i] of + * the input. + * @param dst output array of the same type as src. + */ +CV_EXPORTS_W void transposeND(InputArray src, const std::vector &order, + OutputArray dst); + +/** @brief Performs the matrix transformation of every array element. + +The function cv::transform performs the matrix transformation of every +element of the array src and stores the results in dst : +\f[\texttt{dst} (I) = \texttt{m} \cdot \texttt{src} (I)\f] +(when m.cols=src.channels() ), or +\f[\texttt{dst} (I) = \texttt{m} \cdot [ \texttt{src} (I); 1]\f] +(when m.cols=src.channels()+1 ) + +Every element of the N -channel array src is interpreted as N -element +vector that is transformed using the M x N or M x (N+1) matrix m to +M-element vector - the corresponding element of the output array dst . + +The function may be used for geometrical transformation of +N -dimensional points, arbitrary linear color space transformation (such +as various kinds of RGB to YUV transforms), shuffling the image +channels, and so forth. +@param src input array that must have as many channels (1 to 4) as +m.cols or m.cols-1. +@param dst output array of the same size and depth as src; it has as +many channels as m.rows. +@param m transformation 2x2 or 2x3 floating-point matrix. +@sa perspectiveTransform, getAffineTransform, estimateAffine2D, warpAffine, +warpPerspective +*/ +CV_EXPORTS_W void transform(InputArray src, OutputArray dst, InputArray m); + +/** @brief Performs the perspective matrix transformation of vectors. + +The function cv::perspectiveTransform transforms every element of src by +treating it as a 2D or 3D vector, in the following way: +\f[(x, y, z) \rightarrow (x'/w, y'/w, z'/w)\f] +where +\f[(x', y', z', w') = \texttt{mat} \cdot \begin{bmatrix} x & y & z & 1 +\end{bmatrix}\f] and +\f[w = \fork{w'}{if \(w' \ne 0\)}{\infty}{otherwise}\f] + +Here a 3D vector transformation is shown. In case of a 2D vector +transformation, the z component is omitted. + +@note The function transforms a sparse set of 2D or 3D vectors. If you +want to transform an image using perspective transformation, use +warpPerspective . If you have an inverse problem, that is, you want to +compute the most probable perspective transformation out of several +pairs of corresponding points, you can use getPerspectiveTransform or +findHomography . +@param src input two-channel or three-channel floating-point array; each +element is a 2D/3D vector to be transformed. +@param dst output array of the same size and type as src. +@param m 3x3 or 4x4 floating-point transformation matrix. +@sa transform, warpPerspective, getPerspectiveTransform, findHomography +*/ +CV_EXPORTS_W void perspectiveTransform(InputArray src, OutputArray dst, + InputArray m); + +/** @brief Copies the lower or the upper half of a square matrix to its another +half. + +The function cv::completeSymm copies the lower or the upper half of a square +matrix to its another half. The matrix diagonal remains unchanged: + - \f$\texttt{m}_{ij}=\texttt{m}_{ji}\f$ for \f$i > j\f$ if + lowerToUpper=false + - \f$\texttt{m}_{ij}=\texttt{m}_{ji}\f$ for \f$i < j\f$ if + lowerToUpper=true + +@param m input-output floating-point square matrix. +@param lowerToUpper operation flag; if true, the lower half is copied to +the upper half. Otherwise, the upper half is copied to the lower half. +@sa flip, transpose +*/ +CV_EXPORTS_W void completeSymm(InputOutputArray m, bool lowerToUpper = false); + +/** @brief Initializes a scaled identity matrix. + +The function cv::setIdentity initializes a scaled identity matrix: +\f[\texttt{mtx} (i,j)= \fork{\texttt{value}}{ if \(i=j\)}{0}{otherwise}\f] + +The function can also be emulated using the matrix initializers and the +matrix expressions: +@code + Mat A = Mat::eye(4, 3, CV_32F)*5; + // A will be set to [[5, 0, 0], [0, 5, 0], [0, 0, 5], [0, 0, 0]] +@endcode +@param mtx matrix to initialize (not necessarily square). +@param s value to assign to diagonal elements. +@sa Mat::zeros, Mat::ones, Mat::setTo, Mat::operator= +*/ +CV_EXPORTS_W void setIdentity(InputOutputArray mtx, + const Scalar &s = Scalar(1)); + +/** @brief Returns the determinant of a square floating-point matrix. + +The function cv::determinant calculates and returns the determinant of the +specified matrix. For small matrices ( mtx.cols=mtx.rows\<=3 ), the +direct method is used. For larger matrices, the function uses LU +factorization with partial pivoting. + +For symmetric positively-determined matrices, it is also possible to use +eigen decomposition to calculate the determinant. +@param mtx input matrix that must have CV_32FC1 or CV_64FC1 type and +square size. +@sa trace, invert, solve, eigen, @ref MatrixExpressions +*/ +CV_EXPORTS_W double determinant(InputArray mtx); + +/** @brief Returns the trace of a matrix. + +The function cv::trace returns the sum of the diagonal elements of the +matrix mtx . +\f[\mathrm{tr} ( \texttt{mtx} ) = \sum _i \texttt{mtx} (i,i)\f] +@param mtx input matrix. +*/ +CV_EXPORTS_W Scalar trace(InputArray mtx); + +/** @brief Finds the inverse or pseudo-inverse of a matrix. + +The function cv::invert inverts the matrix src and stores the result in dst +. When the matrix src is singular or non-square, the function calculates +the pseudo-inverse matrix (the dst matrix) so that norm(src\*dst - I) is +minimal, where I is an identity matrix. + +In case of the #DECOMP_LU method, the function returns non-zero value if +the inverse has been successfully calculated and 0 if src is singular. + +In case of the #DECOMP_SVD method, the function returns the inverse +condition number of src (the ratio of the smallest singular value to the +largest singular value) and 0 if src is singular. The SVD method +calculates a pseudo-inverse matrix if src is singular. + +Similarly to #DECOMP_LU, the method #DECOMP_CHOLESKY works only with +non-singular square matrices that should also be symmetrical and +positively defined. In this case, the function stores the inverted +matrix in dst and returns non-zero. Otherwise, it returns 0. + +@param src input floating-point M x N matrix. +@param dst output matrix of N x M size and the same type as src. +@param flags inversion method (cv::DecompTypes) +@sa solve, SVD +*/ +CV_EXPORTS_W double invert(InputArray src, OutputArray dst, + int flags = DECOMP_LU); + +/** @brief Solves one or more linear systems or least-squares problems. + +The function cv::solve solves a linear system or least-squares problem (the +latter is possible with SVD or QR methods, or by specifying the flag +#DECOMP_NORMAL ): +\f[\texttt{dst} = \arg \min _X \| \texttt{src1} \cdot \texttt{X} - +\texttt{src2} \|\f] + +If #DECOMP_LU or #DECOMP_CHOLESKY method is used, the function returns 1 +if src1 (or \f$\texttt{src1}^T\texttt{src1}\f$ ) is non-singular. Otherwise, +it returns 0. In the latter case, dst is not valid. Other methods find a +pseudo-solution in case of a singular left-hand side part. + +@note If you want to find a unity-norm solution of an under-defined +singular system \f$\texttt{src1}\cdot\texttt{dst}=0\f$ , the function solve +will not do the work. Use SVD::solveZ instead. + +@param src1 input matrix on the left-hand side of the system. +@param src2 input matrix on the right-hand side of the system. +@param dst output solution. +@param flags solution (matrix inversion) method (#DecompTypes) +@sa invert, SVD, eigen +*/ +CV_EXPORTS_W bool solve(InputArray src1, InputArray src2, OutputArray dst, + int flags = DECOMP_LU); + +/** @brief Sorts each row or each column of a matrix. + +The function cv::sort sorts each matrix row or each matrix column in +ascending or descending order. So you should pass two operation flags to +get desired behaviour. If you want to sort matrix rows or columns +lexicographically, you can use STL std::sort generic function with the +proper comparison predicate. + +@param src input single-channel array. +@param dst output array of the same size and type as src. +@param flags operation flags, a combination of #SortFlags +@sa sortIdx, randShuffle +*/ +CV_EXPORTS_W void sort(InputArray src, OutputArray dst, int flags); + +/** @brief Sorts each row or each column of a matrix. + +The function cv::sortIdx sorts each matrix row or each matrix column in the +ascending or descending order. So you should pass two operation flags to +get desired behaviour. Instead of reordering the elements themselves, it +stores the indices of sorted elements in the output array. For example: +@code + Mat A = Mat::eye(3,3,CV_32F), B; + sortIdx(A, B, SORT_EVERY_ROW + SORT_ASCENDING); + // B will probably contain + // (because of equal elements in A some permutations are possible): + // [[1, 2, 0], [0, 2, 1], [0, 1, 2]] +@endcode +@param src input single-channel array. +@param dst output integer array of the same size as src. +@param flags operation flags that could be a combination of cv::SortFlags +@sa sort, randShuffle +*/ +CV_EXPORTS_W void sortIdx(InputArray src, OutputArray dst, int flags); + +/** @brief Finds the real roots of a cubic equation. + +The function solveCubic finds the real roots of a cubic equation: +- if coeffs is a 4-element vector: +\f[\texttt{coeffs} [0] x^3 + \texttt{coeffs} [1] x^2 + \texttt{coeffs} [2] x + +\texttt{coeffs} [3] = 0\f] +- if coeffs is a 3-element vector: +\f[x^3 + \texttt{coeffs} [0] x^2 + \texttt{coeffs} [1] x + \texttt{coeffs} +[2] = 0\f] + +The roots are stored in the roots array. +@param coeffs equation coefficients, an array of 3 or 4 elements. +@param roots output array of real roots that has 1 or 3 elements. +@return number of real roots. It can be 0, 1 or 2. +*/ +CV_EXPORTS_W int solveCubic(InputArray coeffs, OutputArray roots); + +/** @brief Finds the real or complex roots of a polynomial equation. + +The function cv::solvePoly finds real and complex roots of a polynomial +equation: +\f[\texttt{coeffs} [n] x^{n} + \texttt{coeffs} [n-1] x^{n-1} + ... + +\texttt{coeffs} [1] x + \texttt{coeffs} [0] = 0\f] +@param coeffs array of polynomial coefficients. +@param roots output (complex) array of roots. +@param maxIters maximum number of iterations the algorithm does. +*/ +CV_EXPORTS_W double solvePoly(InputArray coeffs, OutputArray roots, + int maxIters = 300); + +/** @brief Calculates eigenvalues and eigenvectors of a symmetric matrix. + +The function cv::eigen calculates just eigenvalues, or eigenvalues and +eigenvectors of the symmetric matrix src: +@code + src*eigenvectors.row(i).t() = +eigenvalues.at(i)*eigenvectors.row(i).t() +@endcode + +@note Use cv::eigenNonSymmetric for calculation of real eigenvalues and +eigenvectors of non-symmetric matrix. + +@param src input matrix that must have CV_32FC1 or CV_64FC1 type, square size +and be symmetrical (src ^T^ == src). +@param eigenvalues output vector of eigenvalues of the same type as src; the +eigenvalues are stored in the descending order. +@param eigenvectors output matrix of eigenvectors; it has the same size and type +as src; the eigenvectors are stored as subsequent matrix rows, in the same order +as the corresponding eigenvalues. +@sa eigenNonSymmetric, completeSymm, PCA +*/ +CV_EXPORTS_W bool eigen(InputArray src, OutputArray eigenvalues, + OutputArray eigenvectors = noArray()); + +/** @brief Calculates eigenvalues and eigenvectors of a non-symmetric matrix +(real eigenvalues only). + +@note Assumes real eigenvalues. + +The function calculates eigenvalues and eigenvectors (optional) of the square +matrix src: +@code + src*eigenvectors.row(i).t() = +eigenvalues.at(i)*eigenvectors.row(i).t() +@endcode + +@param src input matrix (CV_32FC1 or CV_64FC1 type). +@param eigenvalues output vector of eigenvalues (type is the same type as src). +@param eigenvectors output matrix of eigenvectors (type is the same type as +src). The eigenvectors are stored as subsequent matrix rows, in the same order +as the corresponding eigenvalues. +@sa eigen +*/ +CV_EXPORTS_W void eigenNonSymmetric(InputArray src, OutputArray eigenvalues, + OutputArray eigenvectors); + +/** @brief Calculates the covariance matrix of a set of vectors. + +The function cv::calcCovarMatrix calculates the covariance matrix and, +optionally, the mean vector of the set of input vectors. +@param samples samples stored as separate matrices +@param nsamples number of samples +@param covar output covariance matrix of the type ctype and square size. +@param mean input or output (depending on the flags) array as the average value +of the input vectors. +@param flags operation flags as a combination of #CovarFlags +@param ctype type of the matrixl; it equals 'CV_64F' by default. +@sa PCA, mulTransposed, Mahalanobis +@todo InputArrayOfArrays +*/ +CV_EXPORTS void calcCovarMatrix(const Mat *samples, int nsamples, Mat &covar, + Mat &mean, int flags, int ctype = CV_64F); + +/** @overload +@note use #COVAR_ROWS or #COVAR_COLS flag +@param samples samples stored as rows/columns of a single matrix. +@param covar output covariance matrix of the type ctype and square size. +@param mean input or output (depending on the flags) array as the average value +of the input vectors. +@param flags operation flags as a combination of #CovarFlags +@param ctype type of the matrixl; it equals 'CV_64F' by default. +*/ +CV_EXPORTS_W void calcCovarMatrix(InputArray samples, OutputArray covar, + InputOutputArray mean, int flags, + int ctype = CV_64F); + +/** wrap PCA::operator() */ +CV_EXPORTS_W void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, int maxComponents = 0); + +/** wrap PCA::operator() and add eigenvalues output parameter */ +CV_EXPORTS_AS(PCACompute2) +void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, OutputArray eigenvalues, + int maxComponents = 0); + +/** wrap PCA::operator() */ +CV_EXPORTS_W void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, double retainedVariance); + +/** wrap PCA::operator() and add eigenvalues output parameter */ +CV_EXPORTS_AS(PCACompute2) +void PCACompute(InputArray data, InputOutputArray mean, + OutputArray eigenvectors, OutputArray eigenvalues, + double retainedVariance); + +/** wrap PCA::project */ +CV_EXPORTS_W void PCAProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result); + +/** wrap PCA::backProject */ +CV_EXPORTS_W void PCABackProject(InputArray data, InputArray mean, + InputArray eigenvectors, OutputArray result); + +/** wrap SVD::compute */ +CV_EXPORTS_W void SVDecomp(InputArray src, OutputArray w, OutputArray u, + OutputArray vt, int flags = 0); + +/** wrap SVD::backSubst */ +CV_EXPORTS_W void SVBackSubst(InputArray w, InputArray u, InputArray vt, + InputArray rhs, OutputArray dst); + +/** @brief Calculates the Mahalanobis distance between two vectors. + +The function cv::Mahalanobis calculates and returns the weighted distance +between two vectors: +\f[d( \texttt{vec1} , \texttt{vec2} )= +\sqrt{\sum_{i,j}{\texttt{icovar(i,j)}\cdot(\texttt{vec1}(I)-\texttt{vec2}(I))\cdot(\texttt{vec1(j)}-\texttt{vec2(j)})} +}\f] The covariance matrix may be calculated using the #calcCovarMatrix function +and then inverted using the invert function (preferably using the #DECOMP_SVD +method, as the most accurate). +@param v1 first 1D input vector. +@param v2 second 1D input vector. +@param icovar inverse covariance matrix. +*/ +CV_EXPORTS_W double Mahalanobis(InputArray v1, InputArray v2, + InputArray icovar); + +/** @brief Performs a forward or inverse Discrete Fourier transform of a 1D or +2D floating-point array. + +The function cv::dft performs one of the following: +- Forward the Fourier transform of a 1D vector of N elements: + \f[Y = F^{(N)} \cdot X,\f] + where \f$F^{(N)}_{jk}=\exp(-2\pi i j k/N)\f$ and \f$i=\sqrt{-1}\f$ +- Inverse the Fourier transform of a 1D vector of N elements: + \f[\begin{array}{l} X'= \left (F^{(N)} \right )^{-1} \cdot Y = \left +(F^{(N)} \right )^* \cdot y \\ X = (1/N) \cdot X, \end{array}\f] where +\f$F^*=\left(\textrm{Re}(F^{(N)})-\textrm{Im}(F^{(N)})\right)^T\f$ +- Forward the 2D Fourier transform of a M x N matrix: + \f[Y = F^{(M)} \cdot X \cdot F^{(N)}\f] +- Inverse the 2D Fourier transform of a M x N matrix: + \f[\begin{array}{l} X'= \left (F^{(M)} \right )^* \cdot Y \cdot \left +(F^{(N)} \right )^* \\ X = \frac{1}{M \cdot N} \cdot X' \end{array}\f] + +In case of real (single-channel) data, the output spectrum of the forward +Fourier transform or input spectrum of the inverse Fourier transform can be +represented in a packed format called *CCS* (complex-conjugate-symmetrical). It +was borrowed from IPL (Intel\* Image Processing Library). Here is how 2D *CCS* +spectrum looks: +\f[\begin{bmatrix} Re Y_{0,0} & Re Y_{0,1} & Im Y_{0,1} & Re Y_{0,2} & Im +Y_{0,2} & \cdots & Re Y_{0,N/2-1} & Im Y_{0,N/2-1} & Re Y_{0,N/2} \\ Re +Y_{1,0} & Re Y_{1,1} & Im Y_{1,1} & Re Y_{1,2} & Im Y_{1,2} & \cdots & Re +Y_{1,N/2-1} & Im Y_{1,N/2-1} & Re Y_{1,N/2} \\ Im Y_{1,0} & Re Y_{2,1} & Im +Y_{2,1} & Re Y_{2,2} & Im Y_{2,2} & \cdots & Re Y_{2,N/2-1} & Im Y_{2,N/2-1} & +Im Y_{1,N/2} \\ \hdotsfor{9} \\ Re Y_{M/2-1,0} & Re Y_{M-3,1} & Im Y_{M-3,1} +& \hdotsfor{3} & Re Y_{M-3,N/2-1} & Im Y_{M-3,N/2-1}& Re Y_{M/2-1,N/2} \\ Im +Y_{M/2-1,0} & Re Y_{M-2,1} & Im Y_{M-2,1} & \hdotsfor{3} & Re Y_{M-2,N/2-1} & +Im Y_{M-2,N/2-1}& Im Y_{M/2-1,N/2} \\ Re Y_{M/2,0} & Re Y_{M-1,1} & Im +Y_{M-1,1} & \hdotsfor{3} & Re Y_{M-1,N/2-1} & Im Y_{M-1,N/2-1}& Re Y_{M/2,N/2} +\end{bmatrix}\f] + +In case of 1D transform of a real vector, the output looks like the first row of +the matrix above. + +So, the function chooses an operation mode depending on the flags and size of +the input array: +- If #DFT_ROWS is set or the input array has a single row or single column, +the function performs a 1D forward or inverse transform of each row of a matrix +when #DFT_ROWS is set. Otherwise, it performs a 2D transform. +- If the input array is real and #DFT_INVERSE is not set, the function +performs a forward 1D or 2D transform: + - When #DFT_COMPLEX_OUTPUT is set, the output is a complex matrix of the +same size as input. + - When #DFT_COMPLEX_OUTPUT is not set, the output is a real matrix of the +same size as input. In case of 2D transform, it uses the packed format as shown +above. In case of a single 1D transform, it looks like the first row of the +matrix above. In case of multiple 1D transforms (when using the #DFT_ROWS flag), +each row of the output matrix looks like the first row of the matrix above. +- If the input array is complex and either #DFT_INVERSE or #DFT_REAL_OUTPUT +are not set, the output is a complex array of the same size as input. The +function performs a forward or inverse 1D or 2D transform of the whole input +array or each row of the input array independently, depending on the flags +DFT_INVERSE and DFT_ROWS. +- When #DFT_INVERSE is set and the input array is real, or it is complex but +#DFT_REAL_OUTPUT is set, the output is a real array of the same size as input. +The function performs a 1D or 2D inverse transformation of the whole input array +or each individual row, depending on the flags #DFT_INVERSE and #DFT_ROWS. + +If #DFT_SCALE is set, the scaling is done after the transformation. + +Unlike dct, the function supports arrays of arbitrary size. But only those +arrays are processed efficiently, whose sizes can be factorized in a product of +small prime numbers (2, 3, and 5 in the current implementation). Such an +efficient DFT size can be calculated using the getOptimalDFTSize method. + +The sample below illustrates how to calculate a DFT-based convolution of two 2D +real arrays: +@code + void convolveDFT(InputArray A, InputArray B, OutputArray C) + { + // reallocate the output array if needed + C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type()); + Size dftSize; + // calculate the size of DFT transform + dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1); + dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1); + + // allocate temporary buffers and initialize them with 0's + Mat tempA(dftSize, A.type(), Scalar::all(0)); + Mat tempB(dftSize, B.type(), Scalar::all(0)); + + // copy A and B to the top-left corners of tempA and tempB, respectively + Mat roiA(tempA, Rect(0,0,A.cols,A.rows)); + A.copyTo(roiA); + Mat roiB(tempB, Rect(0,0,B.cols,B.rows)); + B.copyTo(roiB); + + // now transform the padded A & B in-place; + // use "nonzeroRows" hint for faster processing + dft(tempA, tempA, 0, A.rows); + dft(tempB, tempB, 0, B.rows); + + // multiply the spectrums; + // the function handles packed spectrum representations well + mulSpectrums(tempA, tempB, tempA); + + // transform the product back from the frequency domain. + // Even though all the result rows will be non-zero, + // you need only the first C.rows of them, and thus you + // pass nonzeroRows == C.rows + dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows); + + // now copy the result back to C. + tempA(Rect(0, 0, C.cols, C.rows)).copyTo(C); + + // all the temporary buffers will be deallocated automatically + } +@endcode +To optimize this sample, consider the following approaches: +- Since nonzeroRows != 0 is passed to the forward transform calls and since A +and B are copied to the top-left corners of tempA and tempB, respectively, it is +not necessary to clear the whole tempA and tempB. It is only necessary to clear +the tempA.cols - A.cols ( tempB.cols - B.cols) rightmost columns of the +matrices. +- This DFT-based convolution does not have to be applied to the whole big +arrays, especially if B is significantly smaller than A or vice versa. Instead, +you can calculate convolution by parts. To do this, you need to split the output +array C into multiple tiles. For each tile, estimate which parts of A and B are +required to calculate convolution in this tile. If the tiles in C are too small, +the speed will decrease a lot because of repeated work. In the ultimate case, +when each tile in C is a single pixel, the algorithm becomes equivalent to the +naive convolution algorithm. If the tiles are too big, the temporary arrays +tempA and tempB become too big and there is also a slowdown because of bad cache +locality. So, there is an optimal tile size somewhere in the middle. +- If different tiles in C can be calculated in parallel and, thus, the +convolution is done by parts, the loop can be threaded. + +All of the above improvements have been implemented in #matchTemplate and +#filter2D . Therefore, by using them, you can get the performance even better +than with the above theoretically optimal implementation. Though, those two +functions actually calculate cross-correlation, not convolution, so you need to +"flip" the second convolution operand B vertically and horizontally using flip . +@note +- An example using the discrete fourier transform can be found at + opencv_source_code/samples/cpp/dft.cpp +- (Python) An example using the dft functionality to perform Wiener +deconvolution can be found at opencv_source/samples/python/deconvolution.py +- (Python) An example rearranging the quadrants of a Fourier image can be +found at opencv_source/samples/python/dft.py +@param src input array that could be real or complex. +@param dst output array whose size and type depends on the flags . +@param flags transformation flags, representing a combination of the #DftFlags +@param nonzeroRows when the parameter is not zero, the function assumes that +only the first nonzeroRows rows of the input array (#DFT_INVERSE is not set) or +only the first nonzeroRows of the output array (#DFT_INVERSE is set) contain +non-zeros, thus, the function can handle the rest of the rows more efficiently +and save some time; this technique is very useful for calculating array +cross-correlation or convolution using DFT. +@sa dct, getOptimalDFTSize, mulSpectrums, filter2D, matchTemplate, flip, +cartToPolar, magnitude, phase +*/ +CV_EXPORTS_W void dft(InputArray src, OutputArray dst, int flags = 0, + int nonzeroRows = 0); + +/** @brief Calculates the inverse Discrete Fourier Transform of a 1D or 2D +array. + +idft(src, dst, flags) is equivalent to dft(src, dst, flags | #DFT_INVERSE) . +@note None of dft and idft scales the result by default. So, you should pass +#DFT_SCALE to one of dft or idft explicitly to make these transforms mutually +inverse. +@sa dft, dct, idct, mulSpectrums, getOptimalDFTSize +@param src input floating-point real or complex array. +@param dst output array whose size and type depend on the flags. +@param flags operation flags (see dft and #DftFlags). +@param nonzeroRows number of dst rows to process; the rest of the rows have +undefined content (see the convolution sample in dft description. +*/ +CV_EXPORTS_W void idft(InputArray src, OutputArray dst, int flags = 0, + int nonzeroRows = 0); + +/** @brief Performs a forward or inverse discrete Cosine transform of 1D or 2D +array. + +The function cv::dct performs a forward or inverse discrete Cosine transform +(DCT) of a 1D or 2D floating-point array: +- Forward Cosine transform of a 1D vector of N elements: + \f[Y = C^{(N)} \cdot X\f] + where + \f[C^{(N)}_{jk}= \sqrt{\alpha_j/N} \cos \left ( \frac{\pi(2k+1)j}{2N} \right +)\f] and + \f$\alpha_0=1\f$, \f$\alpha_j=2\f$ for *j \> 0*. +- Inverse Cosine transform of a 1D vector of N elements: + \f[X = \left (C^{(N)} \right )^{-1} \cdot Y = \left (C^{(N)} \right )^T +\cdot Y\f] (since \f$C^{(N)}\f$ is an orthogonal matrix, \f$C^{(N)} \cdot +\left(C^{(N)}\right)^T = I\f$ ) +- Forward 2D Cosine transform of M x N matrix: + \f[Y = C^{(N)} \cdot X \cdot \left (C^{(N)} \right )^T\f] +- Inverse 2D Cosine transform of M x N matrix: + \f[X = \left (C^{(N)} \right )^T \cdot X \cdot C^{(N)}\f] + +The function chooses the mode of operation by looking at the flags and size of +the input array: +- If (flags & #DCT_INVERSE) == 0, the function does a forward 1D or 2D +transform. Otherwise, it is an inverse 1D or 2D transform. +- If (flags & #DCT_ROWS) != 0, the function performs a 1D transform of each +row. +- If the array is a single column or a single row, the function performs a 1D +transform. +- If none of the above is true, the function performs a 2D transform. + +@note Currently dct supports even-size arrays (2, 4, 6 ...). For data analysis +and approximation, you can pad the array when necessary. Also, the function +performance depends very much, and not monotonically, on the array size (see +getOptimalDFTSize ). In the current implementation DCT of a vector of size N is +calculated via DFT of a vector of size N/2 . Thus, the optimal DCT size N1 \>= N +can be calculated as: +@code + size_t getOptimalDCTSize(size_t N) { return 2*getOptimalDFTSize((N+1)/2); } + N1 = getOptimalDCTSize(N); +@endcode +@param src input floating-point array. +@param dst output array of the same size and type as src . +@param flags transformation flags as a combination of cv::DftFlags (DCT_*) +@sa dft, getOptimalDFTSize, idct +*/ +CV_EXPORTS_W void dct(InputArray src, OutputArray dst, int flags = 0); + +/** @brief Calculates the inverse Discrete Cosine Transform of a 1D or 2D array. + +idct(src, dst, flags) is equivalent to dct(src, dst, flags | DCT_INVERSE). +@param src input floating-point single-channel array. +@param dst output array of the same size and type as src. +@param flags operation flags. +@sa dct, dft, idft, getOptimalDFTSize +*/ +CV_EXPORTS_W void idct(InputArray src, OutputArray dst, int flags = 0); + +/** @brief Performs the per-element multiplication of two Fourier spectrums. + +The function cv::mulSpectrums performs the per-element multiplication of the two +CCS-packed or complex matrices that are results of a real or complex Fourier +transform. + +The function, together with dft and idft, may be used to calculate convolution +(pass conjB=false ) or correlation (pass conjB=true ) of two arrays rapidly. +When the arrays are complex, they are simply multiplied (per element) with an +optional conjugation of the second-array elements. When the arrays are real, +they are assumed to be CCS-packed (see dft for details). +@param a first input array. +@param b second input array of the same size and type as src1 . +@param c output array of the same size and type as src1 . +@param flags operation flags; currently, the only supported flag is +cv::DFT_ROWS, which indicates that each row of src1 and src2 is an independent +1D Fourier spectrum. If you do not want to use this flag, then simply add a `0` +as value. +@param conjB optional flag that conjugates the second input array before the +multiplication (true) or not (false). +*/ +CV_EXPORTS_W void mulSpectrums(InputArray a, InputArray b, OutputArray c, + int flags, bool conjB = false); + +/** @brief Returns the optimal DFT size for a given vector size. + +DFT performance is not a monotonic function of a vector size. Therefore, when +you calculate convolution of two arrays or perform the spectral analysis of an +array, it usually makes sense to pad the input data with zeros to get a bit +larger array that can be transformed much faster than the original one. Arrays +whose size is a power-of-two (2, 4, 8, 16, 32, ...) are the fastest to process. +Though, the arrays whose size is a product of 2's, 3's, and 5's (for example, +300 = 5\*5\*3\*2\*2) are also processed quite efficiently. + +The function cv::getOptimalDFTSize returns the minimum number N that is greater +than or equal to vecsize so that the DFT of a vector of size N can be processed +efficiently. In the current implementation N = 2 ^p^ \* 3 ^q^ \* 5 ^r^ for some +integer p, q, r. + +The function returns a negative number if vecsize is too large (very close to +INT_MAX ). + +While the function cannot be used directly to estimate the optimal vector size +for DCT transform (since the current DCT implementation supports only even-size +vectors), it can be easily processed as getOptimalDFTSize((vecsize+1)/2)\*2. +@param vecsize vector size. +@sa dft, dct, idft, idct, mulSpectrums +*/ +CV_EXPORTS_W int getOptimalDFTSize(int vecsize); + +/** @brief Returns the default random number generator. + +The function cv::theRNG returns the default random number generator. For each +thread, there is a separate random number generator, so you can use the function +safely in multi-thread environments. If you just need to get a single random +number using this generator or initialize an array, you can use randu or randn +instead. But if you are going to generate many random numbers inside a loop, it +is much faster to use this function to retrieve the generator and then use +RNG::operator _Tp() . +@sa RNG, randu, randn +*/ +CV_EXPORTS RNG &theRNG(); + +/** @brief Sets state of default random number generator. + +The function cv::setRNGSeed sets state of default random number generator to +custom value. +@param seed new state for default random number generator +@sa RNG, randu, randn +*/ +CV_EXPORTS_W void setRNGSeed(int seed); + +/** @brief Generates a single uniformly-distributed random number or an array of +random numbers. + +Non-template variant of the function fills the matrix dst with +uniformly-distributed random numbers from the specified range: +\f[\texttt{low} _c \leq \texttt{dst} (I)_c < \texttt{high} _c\f] +@param dst output array of random numbers; the array must be pre-allocated. +@param low inclusive lower boundary of the generated random numbers. +@param high exclusive upper boundary of the generated random numbers. +@sa RNG, randn, theRNG +*/ +CV_EXPORTS_W void randu(InputOutputArray dst, InputArray low, InputArray high); + +/** @brief Fills the array with normally distributed random numbers. + +The function cv::randn fills the matrix dst with normally distributed random +numbers with the specified mean vector and the standard deviation matrix. The +generated random numbers are clipped to fit the value range of the output array +data type. +@param dst output array of random numbers; the array must be pre-allocated and +have 1 to 4 channels. +@param mean mean value (expectation) of the generated random numbers. +@param stddev standard deviation of the generated random numbers; it can be +either a vector (in which case a diagonal standard deviation matrix is assumed) +or a square matrix. +@sa RNG, randu +*/ +CV_EXPORTS_W void randn(InputOutputArray dst, InputArray mean, + InputArray stddev); + +/** @brief Shuffles the array elements randomly. + +The function cv::randShuffle shuffles the specified 1D array by randomly +choosing pairs of elements and swapping them. The number of such swap operations +will be dst.rows\*dst.cols\*iterFactor . +@param dst input/output numerical 1D array. +@param iterFactor scale factor that determines the number of random swap +operations (see the details below). +@param rng optional random number generator used for shuffling; if it is zero, +theRNG () is used instead. +@sa RNG, sort +*/ +CV_EXPORTS_W void randShuffle(InputOutputArray dst, double iterFactor = 1., + RNG *rng = 0); + +/** @brief Principal Component Analysis + +The class is used to calculate a special basis for a set of vectors. The +basis will consist of eigenvectors of the covariance matrix calculated +from the input set of vectors. The class %PCA can also transform +vectors to/from the new coordinate space defined by the basis. Usually, +in this new coordinate system, each vector from the original set (and +any linear combination of such vectors) can be quite accurately +approximated by taking its first few components, corresponding to the +eigenvectors of the largest eigenvalues of the covariance matrix. +Geometrically it means that you calculate a projection of the vector to +a subspace formed by a few eigenvectors corresponding to the dominant +eigenvalues of the covariance matrix. And usually such a projection is +very close to the original vector. So, you can represent the original +vector from a high-dimensional space with a much shorter vector +consisting of the projected vector's coordinates in the subspace. Such a +transformation is also known as Karhunen-Loeve Transform, or KLT. +See http://en.wikipedia.org/wiki/Principal_component_analysis + +The sample below is the function that takes two matrices. The first +function stores a set of vectors (a row per vector) that is used to +calculate PCA. The second function stores another "test" set of vectors +(a row per vector). First, these vectors are compressed with PCA, then +reconstructed back, and then the reconstruction error norm is computed +and printed for each vector. : + +@code{.cpp} +using namespace cv; + +PCA compressPCA(const Mat& pcaset, int maxComponents, + const Mat& testset, Mat& compressed) +{ + PCA pca(pcaset, // pass the data + Mat(), // we do not have a pre-computed mean vector, + // so let the PCA engine to compute it + PCA::DATA_AS_ROW, // indicate that the vectors + // are stored as matrix rows + // (use PCA::DATA_AS_COL if the vectors are + // the matrix columns) + maxComponents // specify, how many principal components to retain + ); + // if there is no test data, just return the computed basis, ready-to-use + if( !testset.data ) + return pca; + CV_Assert( testset.cols == pcaset.cols ); + + compressed.create(testset.rows, maxComponents, testset.type()); + + Mat reconstructed; + for( int i = 0; i < testset.rows; i++ ) + { + Mat vec = testset.row(i), coeffs = compressed.row(i), reconstructed; + // compress the vector, the result will be stored + // in the i-th row of the output matrix + pca.project(vec, coeffs); + // and then reconstruct it + pca.backProject(coeffs, reconstructed); + // and measure the error + printf("%d. diff = %g\n", i, norm(vec, reconstructed, NORM_L2)); + } + return pca; +} +@endcode +@sa calcCovarMatrix, mulTransposed, SVD, dft, dct +*/ +class CV_EXPORTS PCA { +public: + enum Flags { + DATA_AS_ROW = + 0, //!< indicates that the input samples are stored as matrix rows + DATA_AS_COL = + 1, //!< indicates that the input samples are stored as matrix columns + USE_AVG = 2 //! + }; + + /** @brief default constructor + + The default constructor initializes an empty %PCA structure. The other + constructors initialize the structure and call PCA::operator()(). + */ + PCA(); + + /** @overload + @param data input samples stored as matrix rows or matrix columns. + @param mean optional mean value; if the matrix is empty (@c noArray()), + the mean is computed from the data. + @param flags operation flags; currently the parameter is only used to + specify the data layout (PCA::Flags) + @param maxComponents maximum number of components that %PCA should + retain; by default, all the components are retained. + */ + PCA(InputArray data, InputArray mean, int flags, int maxComponents = 0); + + /** @overload + @param data input samples stored as matrix rows or matrix columns. + @param mean optional mean value; if the matrix is empty (noArray()), + the mean is computed from the data. + @param flags operation flags; currently the parameter is only used to + specify the data layout (PCA::Flags) + @param retainedVariance Percentage of variance that PCA should retain. + Using this parameter will let the PCA decided how many components to + retain but it will always keep at least 2. + */ + PCA(InputArray data, InputArray mean, int flags, double retainedVariance); + + /** @brief performs %PCA + + The operator performs %PCA of the supplied dataset. It is safe to reuse + the same PCA structure for multiple datasets. That is, if the structure + has been previously used with another dataset, the existing internal + data is reclaimed and the new @ref eigenvalues, @ref eigenvectors and @ref + mean are allocated and computed. + + The computed @ref eigenvalues are sorted from the largest to the smallest and + the corresponding @ref eigenvectors are stored as eigenvectors rows. + + @param data input samples stored as the matrix rows or as the matrix + columns. + @param mean optional mean value; if the matrix is empty (noArray()), + the mean is computed from the data. + @param flags operation flags; currently the parameter is only used to + specify the data layout. (Flags) + @param maxComponents maximum number of components that PCA should + retain; by default, all the components are retained. + */ + PCA &operator()(InputArray data, InputArray mean, int flags, + int maxComponents = 0); + + /** @overload + @param data input samples stored as the matrix rows or as the matrix + columns. + @param mean optional mean value; if the matrix is empty (noArray()), + the mean is computed from the data. + @param flags operation flags; currently the parameter is only used to + specify the data layout. (PCA::Flags) + @param retainedVariance Percentage of variance that %PCA should retain. + Using this parameter will let the %PCA decided how many components to + retain but it will always keep at least 2. + */ + PCA &operator()(InputArray data, InputArray mean, int flags, + double retainedVariance); + + /** @brief Projects vector(s) to the principal component subspace. + + The methods project one or more vectors to the principal component + subspace, where each vector projection is represented by coefficients in + the principal component basis. The first form of the method returns the + matrix that the second form writes to the result. So the first form can + be used as a part of expression while the second form can be more + efficient in a processing loop. + @param vec input vector(s); must have the same dimensionality and the + same layout as the input data used at %PCA phase, that is, if + DATA_AS_ROW are specified, then `vec.cols==data.cols` + (vector dimensionality) and `vec.rows` is the number of vectors to + project, and the same is true for the PCA::DATA_AS_COL case. + */ + Mat project(InputArray vec) const; + + /** @overload + @param vec input vector(s); must have the same dimensionality and the + same layout as the input data used at PCA phase, that is, if + DATA_AS_ROW are specified, then `vec.cols==data.cols` + (vector dimensionality) and `vec.rows` is the number of vectors to + project, and the same is true for the PCA::DATA_AS_COL case. + @param result output vectors; in case of PCA::DATA_AS_COL, the + output matrix has as many columns as the number of input vectors, this + means that `result.cols==vec.cols` and the number of rows match the + number of principal components (for example, `maxComponents` parameter + passed to the constructor). + */ + void project(InputArray vec, OutputArray result) const; + + /** @brief Reconstructs vectors from their PC projections. + + The methods are inverse operations to PCA::project. They take PC + coordinates of projected vectors and reconstruct the original vectors. + Unless all the principal components have been retained, the + reconstructed vectors are different from the originals. But typically, + the difference is small if the number of components is large enough (but + still much smaller than the original vector dimensionality). As a + result, PCA is used. + @param vec coordinates of the vectors in the principal component + subspace, the layout and size are the same as of PCA::project output + vectors. + */ + Mat backProject(InputArray vec) const; + + /** @overload + @param vec coordinates of the vectors in the principal component + subspace, the layout and size are the same as of PCA::project output + vectors. + @param result reconstructed vectors; the layout and size are the same as + of PCA::project input vectors. + */ + void backProject(InputArray vec, OutputArray result) const; + + /** @brief write PCA objects + + Writes @ref eigenvalues @ref eigenvectors and @ref mean to specified + FileStorage + */ + void write(FileStorage &fs) const; + + /** @brief load PCA objects + + Loads @ref eigenvalues @ref eigenvectors and @ref mean from specified FileNode + */ + void read(const FileNode &fn); + + Mat eigenvectors; //!< eigenvectors of the covariation matrix + Mat eigenvalues; //!< eigenvalues of the covariation matrix + Mat mean; //!< mean value subtracted before the projection and added after the + //!< back projection +}; + +/** @example samples/cpp/pca.cpp +An example using %PCA for dimensionality reduction while maintaining an amount +of variance +*/ + +/** @example +samples/cpp/tutorial_code/ml/introduction_to_pca/introduction_to_pca.cpp Check +@ref tutorial_introduction_to_pca "the corresponding tutorial" for more details +*/ + +/** +@brief Linear Discriminant Analysis +@todo document this class +*/ +class CV_EXPORTS LDA { +public: + /** @brief constructor + Initializes a LDA with num_components (default 0). + */ + explicit LDA(int num_components = 0); + + /** Initializes and performs a Discriminant Analysis with Fisher's + Optimization Criterion on given data in src and corresponding labels + in labels. If 0 (or less) number of components are given, they are + automatically determined for given data in computation. + */ + LDA(InputArrayOfArrays src, InputArray labels, int num_components = 0); + + /** Serializes this object to a given filename. + */ + void save(const String &filename) const; + + /** Deserializes this object from a given filename. + */ + void load(const String &filename); + + /** Serializes this object to a given cv::FileStorage. + */ + void save(FileStorage &fs) const; + + /** Deserializes this object from a given cv::FileStorage. + */ + void load(const FileStorage &node); + + /** destructor + */ + ~LDA(); + + /** Compute the discriminants for data in src (row aligned) and labels. + */ + void compute(InputArrayOfArrays src, InputArray labels); + + /** Projects samples into the LDA subspace. + src may be one or more row aligned samples. + */ + Mat project(InputArray src); + + /** Reconstructs projections from the LDA subspace. + src may be one or more row aligned projections. + */ + Mat reconstruct(InputArray src); + + /** Returns the eigenvectors of this LDA. + */ + Mat eigenvectors() const { return _eigenvectors; } + + /** Returns the eigenvalues of this LDA. + */ + Mat eigenvalues() const { return _eigenvalues; } + + static Mat subspaceProject(InputArray W, InputArray mean, InputArray src); + static Mat subspaceReconstruct(InputArray W, InputArray mean, InputArray src); + +protected: + int _num_components; + Mat _eigenvectors; + Mat _eigenvalues; + void lda(InputArrayOfArrays src, InputArray labels); +}; + +/** @brief Singular Value Decomposition + +Class for computing Singular Value Decomposition of a floating-point +matrix. The Singular Value Decomposition is used to solve least-square +problems, under-determined linear systems, invert matrices, compute +condition numbers, and so on. + +If you want to compute a condition number of a matrix or an absolute value of +its determinant, you do not need `u` and `vt`. You can pass +flags=SVD::NO_UV|... . Another flag SVD::FULL_UV indicates that full-size u +and vt must be computed, which is not necessary most of the time. + +@sa invert, solve, eigen, determinant +*/ +class CV_EXPORTS SVD { +public: + enum Flags { + /** allow the algorithm to modify the decomposed matrix; it can save space + and speed up processing. currently ignored. */ + MODIFY_A = 1, + /** indicates that only a vector of singular values `w` is to be processed, + while u and vt will be set to empty matrices */ + NO_UV = 2, + /** when the matrix is not square, by default the algorithm produces u and + vt matrices of sufficiently large size for the further A reconstruction; + if, however, FULL_UV flag is specified, u and vt will be full-size square + orthogonal matrices.*/ + FULL_UV = 4 + }; + + /** @brief the default constructor + + initializes an empty SVD structure + */ + SVD(); + + /** @overload + initializes an empty SVD structure and then calls SVD::operator() + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. + @param flags operation flags (SVD::Flags) + */ + SVD(InputArray src, int flags = 0); + + /** @brief the operator that performs SVD. The previously allocated u, w and + vt are released. + + The operator performs the singular value decomposition of the supplied + matrix. The u,`vt` , and the vector of singular values w are stored in + the structure. The same SVD structure can be reused many times with + different matrices. Each time, if needed, the previous u,`vt` , and w + are reclaimed and the new matrices are created, which is all handled by + Mat::create. + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. + @param flags operation flags (SVD::Flags) + */ + SVD &operator()(InputArray src, int flags = 0); + + /** @brief decomposes matrix and stores the results to user-provided matrices + + The methods/functions perform SVD of matrix. Unlike SVD::SVD constructor + and SVD::operator(), they store the results to the user-provided + matrices: + + @code{.cpp} + Mat A, w, u, vt; + SVD::compute(A, w, u, vt); + @endcode + + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. + @param w calculated singular values + @param u calculated left singular vectors + @param vt transposed matrix of right singular vectors + @param flags operation flags - see SVD::Flags. + */ + static void compute(InputArray src, OutputArray w, OutputArray u, + OutputArray vt, int flags = 0); + + /** @overload + computes singular values of a matrix + @param src decomposed matrix. The depth has to be CV_32F or CV_64F. + @param w calculated singular values + @param flags operation flags - see SVD::Flags. + */ + static void compute(InputArray src, OutputArray w, int flags = 0); + + /** @brief performs back substitution + */ + static void backSubst(InputArray w, InputArray u, InputArray vt, + InputArray rhs, OutputArray dst); + + /** @brief solves an under-determined singular linear system + + The method finds a unit-length solution x of a singular linear system + A\*x = 0. Depending on the rank of A, there can be no solutions, a + single solution or an infinite number of solutions. In general, the + algorithm solves the following problem: + \f[dst = \arg \min _{x: \| x \| =1} \| src \cdot x \|\f] + @param src left-hand-side matrix. + @param dst found solution. + */ + static void solveZ(InputArray src, OutputArray dst); + + /** @brief performs a singular value back substitution. + + The method calculates a back substitution for the specified right-hand + side: + + \f[\texttt{x} = \texttt{vt} ^T \cdot diag( \texttt{w} )^{-1} \cdot + \texttt{u} ^T \cdot \texttt{rhs} \sim \texttt{A} ^{-1} \cdot \texttt{rhs}\f] + + Using this technique you can either get a very accurate solution of the + convenient linear system, or the best (in the least-squares terms) + pseudo-solution of an overdetermined linear system. + + @param rhs right-hand side of a linear system (u\*w\*v')\*dst = rhs to + be solved, where A has been previously decomposed. + + @param dst found solution of the system. + + @note Explicit SVD with the further back substitution only makes sense + if you need to solve many linear systems with the same left-hand side + (for example, src ). If all you need is to solve a single system + (possibly with multiple rhs immediately available), simply call solve + add pass #DECOMP_SVD there. It does absolutely the same thing. + */ + void backSubst(InputArray rhs, OutputArray dst) const; + + /** @todo document */ + template + static void compute(const Matx<_Tp, m, n> &a, Matx<_Tp, nm, 1> &w, + Matx<_Tp, m, nm> &u, Matx<_Tp, n, nm> &vt); + + /** @todo document */ + template + static void compute(const Matx<_Tp, m, n> &a, Matx<_Tp, nm, 1> &w); + + /** @todo document */ + template + static void backSubst(const Matx<_Tp, nm, 1> &w, const Matx<_Tp, m, nm> &u, + const Matx<_Tp, n, nm> &vt, const Matx<_Tp, m, nb> &rhs, + Matx<_Tp, n, nb> &dst); + + Mat u, w, vt; +}; + +/** @brief Random Number Generator + +Random number generator. It encapsulates the state (currently, a 64-bit +integer) and has methods to return scalar random values and to fill +arrays with random values. Currently it supports uniform and Gaussian +(normal) distributions. The generator uses Multiply-With-Carry +algorithm, introduced by G. Marsaglia ( + ). +Gaussian-distribution random numbers are generated using the Ziggurat +algorithm ( ), +introduced by G. Marsaglia and W. W. Tsang. +*/ +class CV_EXPORTS RNG { +public: + enum { UNIFORM = 0, NORMAL = 1 }; + + /** @brief constructor + + These are the RNG constructors. The first form sets the state to some + pre-defined value, equal to 2\*\*32-1 in the current implementation. The + second form sets the state to the specified value. If you passed state=0 + , the constructor uses the above default value instead to avoid the + singular random number sequence, consisting of all zeros. + */ + RNG(); + /** @overload + @param state 64-bit value used to initialize the RNG. + */ + RNG(uint64 state); + /**The method updates the state using the MWC algorithm and returns the + next 32-bit random number.*/ + unsigned next(); + + /**Each of the methods updates the state using the MWC algorithm and + returns the next random number of the specified type. In case of integer + types, the returned number is from the available value range for the + specified type. In case of floating-point types, the returned value is + from [0,1) range. + */ + operator uchar(); + /** @overload */ + operator schar(); + /** @overload */ + operator ushort(); + /** @overload */ + operator short(); + /** @overload */ + operator unsigned(); + /** @overload */ + operator int(); + /** @overload */ + operator float(); + /** @overload */ + operator double(); + + /** @brief returns a random integer sampled uniformly from [0, N). + + The methods transform the state using the MWC algorithm and return the + next random number. The first form is equivalent to RNG::next . The + second form returns the random number modulo N, which means that the + result is in the range [0, N) . + */ + unsigned operator()(); + /** @overload + @param N upper non-inclusive boundary of the returned random number. + */ + unsigned operator()(unsigned N); + + /** @brief returns uniformly distributed integer random number from [a,b) + range + + The methods transform the state using the MWC algorithm and return the + next uniformly-distributed random number of the specified type, deduced + from the input parameter type, from the range [a, b) . There is a nuance + illustrated by the following sample: + + @code{.cpp} + RNG rng; + + // always produces 0 + double a = rng.uniform(0, 1); + + // produces double from [0, 1) + double a1 = rng.uniform((double)0, (double)1); + + // produces float from [0, 1) + float b = rng.uniform(0.f, 1.f); + + // produces double from [0, 1) + double c = rng.uniform(0., 1.); + + // may cause compiler error because of ambiguity: + // RNG::uniform(0, (int)0.999999)? or RNG::uniform((double)0, 0.99999)? + double d = rng.uniform(0, 0.999999); + @endcode + + The compiler does not take into account the type of the variable to + which you assign the result of RNG::uniform . The only thing that + matters to the compiler is the type of a and b parameters. So, if you + want a floating-point random number, but the range boundaries are + integer numbers, either put dots in the end, if they are constants, or + use explicit type cast operators, as in the a1 initialization above. + @param a lower inclusive boundary of the returned random number. + @param b upper non-inclusive boundary of the returned random number. + */ + int uniform(int a, int b); + /** @overload */ + float uniform(float a, float b); + /** @overload */ + double uniform(double a, double b); + + /** @brief Fills arrays with random numbers. + + @param mat 2D or N-dimensional matrix; currently matrices with more than + 4 channels are not supported by the methods, use Mat::reshape as a + possible workaround. + @param distType distribution type, RNG::UNIFORM or RNG::NORMAL. + @param a first distribution parameter; in case of the uniform + distribution, this is an inclusive lower boundary, in case of the normal + distribution, this is a mean value. + @param b second distribution parameter; in case of the uniform + distribution, this is a non-inclusive upper boundary, in case of the + normal distribution, this is a standard deviation (diagonal of the + standard deviation matrix or the full standard deviation matrix). + @param saturateRange pre-saturation flag; for uniform distribution only; + if true, the method will first convert a and b to the acceptable value + range (according to the mat datatype) and then will generate uniformly + distributed random numbers within the range [saturate(a), saturate(b)), + if saturateRange=false, the method will generate uniformly distributed + random numbers in the original range [a, b) and then will saturate them, + it means, for example, that + theRNG().fill(mat_8u, RNG::UNIFORM, -DBL_MAX, DBL_MAX) will likely + produce array mostly filled with 0's and 255's, since the range (0, 255) + is significantly smaller than [-DBL_MAX, DBL_MAX). + + Each of the methods fills the matrix with the random values from the + specified distribution. As the new numbers are generated, the RNG state + is updated accordingly. In case of multiple-channel images, every + channel is filled independently, which means that RNG cannot generate + samples from the multi-dimensional Gaussian distribution with + non-diagonal covariance matrix directly. To do that, the method + generates samples from multi-dimensional standard Gaussian distribution + with zero mean and identity covariation matrix, and then transforms them + using transform to get samples from the specified Gaussian distribution. + */ + void fill(InputOutputArray mat, int distType, InputArray a, InputArray b, + bool saturateRange = false); + + /** @brief Returns the next random number sampled from the Gaussian + distribution + @param sigma standard deviation of the distribution. + + The method transforms the state using the MWC algorithm and returns the + next random number from the Gaussian distribution N(0,sigma) . That is, + the mean value of the returned random numbers is zero and the standard + deviation is the specified sigma . + */ + double gaussian(double sigma); + + uint64 state; + + bool operator==(const RNG &other) const; +}; + +/** @brief Mersenne Twister random number generator + +Inspired by +http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c +@todo document +*/ +class CV_EXPORTS RNG_MT19937 { +public: + RNG_MT19937(); + RNG_MT19937(unsigned s); + void seed(unsigned s); + + unsigned next(); + + operator int(); + operator unsigned(); + operator float(); + operator double(); + + unsigned operator()(unsigned N); + unsigned operator()(); + + /** @brief returns uniformly distributed integer random number from [a,b) + * range*/ + int uniform(int a, int b); + /** @brief returns uniformly distributed floating-point random number from + * [a,b) range*/ + float uniform(float a, float b); + /** @brief returns uniformly distributed double-precision floating-point + * random number from [a,b) range*/ + double uniform(double a, double b); + +private: + enum PeriodParameters { N = 624, M = 397 }; + unsigned state[N]; + int mti; +}; + +//! @} core_array + +//! @addtogroup core_cluster +//! @{ + +//! k-means flags +enum KmeansFlags { + /** Select random initial centers in each attempt.*/ + KMEANS_RANDOM_CENTERS = 0, + /** Use kmeans++ center initialization by Arthur and Vassilvitskii + [Arthur2007].*/ + KMEANS_PP_CENTERS = 2, + /** During the first (and possibly the only) attempt, use the + user-supplied labels instead of computing them from the initial centers. + For the second and further attempts, use the random or semi-random centers. + Use one of KMEANS_\*_CENTERS flag to specify the exact method.*/ + KMEANS_USE_INITIAL_LABELS = 1 +}; + +/** @example samples/cpp/kmeans.cpp +An example on k-means clustering +*/ + +/** @brief Finds centers of clusters and groups input samples around the +clusters. + +The function kmeans implements a k-means algorithm that finds the centers of +cluster_count clusters and groups the input samples around the clusters. As an +output, \f$\texttt{bestLabels}_i\f$ contains a 0-based cluster index for the +sample stored in the \f$i^{th}\f$ row of the samples matrix. + +@note +- (Python) An example on k-means clustering can be found at + opencv_source_code/samples/python/kmeans.py +@param data Data for clustering. An array of N-Dimensional points with float +coordinates is needed. Examples of this array can be: +- Mat points(count, 2, CV_32F); +- Mat points(count, 1, CV_32FC2); +- Mat points(1, count, CV_32FC2); +- std::vector\ points(sampleCount); +@param K Number of clusters to split the set by. +@param bestLabels Input/output integer array that stores the cluster indices for +every sample. +@param criteria The algorithm termination criteria, that is, the maximum number +of iterations and/or the desired accuracy. The accuracy is specified as +criteria.epsilon. As soon as each of the cluster centers moves by less than +criteria.epsilon on some iteration, the algorithm stops. +@param attempts Flag to specify the number of times the algorithm is executed +using different initial labellings. The algorithm returns the labels that yield +the best compactness (see the last function parameter). +@param flags Flag that can take values of cv::KmeansFlags +@param centers Output matrix of the cluster centers, one row per each cluster +center. +@return The function returns the compactness measure that is computed as +\f[\sum _i \| \texttt{samples} _i - \texttt{centers} _{ \texttt{labels} _i} \| +^2\f] after every attempt. The best (minimum) value is chosen and the +corresponding labels and the compactness value are returned by the function. +Basically, you can use only the core of the function, set the number of attempts +to 1, initialize labels each time using a custom algorithm, pass them with the ( +flags = #KMEANS_USE_INITIAL_LABELS ) flag, and then choose the best +(most-compact) clustering. +*/ +CV_EXPORTS_W double kmeans(InputArray data, int K, InputOutputArray bestLabels, + TermCriteria criteria, int attempts, int flags, + OutputArray centers = noArray()); + +//! @} core_cluster + +//! @addtogroup core_basic +//! @{ + +/////////////////////////////// Formatted output of cv::Mat +////////////////////////////// + +/** @todo document */ +class CV_EXPORTS Formatted { +public: + virtual const char *next() = 0; + virtual void reset() = 0; + virtual ~Formatted(); +}; + +/** @todo document */ +class CV_EXPORTS Formatter { +public: + enum FormatType { + FMT_DEFAULT = 0, + FMT_MATLAB = 1, + FMT_CSV = 2, + FMT_PYTHON = 3, + FMT_NUMPY = 4, + FMT_C = 5 + }; + + virtual ~Formatter(); + + virtual Ptr format(const Mat &mtx) const = 0; + + virtual void set16fPrecision(int p = 4) = 0; + virtual void set32fPrecision(int p = 8) = 0; + virtual void set64fPrecision(int p = 16) = 0; + virtual void setMultiline(bool ml = true) = 0; + + static Ptr get(Formatter::FormatType fmt = FMT_DEFAULT); +}; + +static inline String &operator<<(String &out, Ptr fmtd) { + fmtd->reset(); + for (const char *str = fmtd->next(); str; str = fmtd->next()) + out += cv::String(str); + return out; +} + +static inline String &operator<<(String &out, const Mat &mtx) { + return out << Formatter::get()->format(mtx); +} + +//////////////////////////////////////// Algorithm +/////////////////////////////////////// + +class CV_EXPORTS Algorithm; + +template struct ParamType {}; + +/** @brief This is a base class for all more or less complex algorithms in +OpenCV + +especially for classes of algorithms, for which there can be multiple +implementations. The examples are stereo correspondence (for which there are +algorithms like block matching, semi-global block matching, graph-cut etc.), +background subtraction (which can be done using mixture-of-gaussians models, +codebook-based algorithm etc.), optical flow (block matching, Lucas-Kanade, +Horn-Schunck etc.). + +Here is example of SimpleBlobDetector use in your application via Algorithm +interface: +@snippet snippets/core_various.cpp Algorithm +*/ +class CV_EXPORTS_W Algorithm { +public: + Algorithm(); + virtual ~Algorithm(); + + /** @brief Clears the algorithm state + */ + CV_WRAP virtual void clear() {} + + /** @brief Stores algorithm parameters in a file storage + */ + CV_WRAP virtual void write(FileStorage &fs) const { CV_UNUSED(fs); } + + /** + * @overload + */ + CV_WRAP void write(FileStorage &fs, const String &name) const; +#if CV_VERSION_MAJOR < 5 + /** @deprecated */ + void write(const Ptr &fs, const String &name = String()) const; +#endif + + /** @brief Reads algorithm parameters from a file storage + */ + CV_WRAP virtual void read(const FileNode &fn) { CV_UNUSED(fn); } + + /** @brief Returns true if the Algorithm is empty (e.g. in the very beginning + * or after unsuccessful read + */ + CV_WRAP virtual bool empty() const { return false; } + + /** @brief Reads algorithm from the file node + + This is static template method of Algorithm. It's usage is following (in the + case of SVM): + @code + cv::FileStorage fsRead("example.xml", FileStorage::READ); + Ptr svm = Algorithm::read(fsRead.root()); + @endcode + In order to make this method work, the derived class must overwrite + Algorithm::read(const FileNode& fn) and also have static create() method + without parameters (or with all the optional parameters) + */ + template static Ptr<_Tp> read(const FileNode &fn) { + Ptr<_Tp> obj = _Tp::create(); + obj->read(fn); + return !obj->empty() ? obj : Ptr<_Tp>(); + } + + /** @brief Loads algorithm from the file + + @param filename Name of the file to read. + @param objname The optional name of the node to read (if empty, the first + top-level node will be used) + + This is static template method of Algorithm. It's usage is following (in the + case of SVM): + @code + Ptr svm = Algorithm::load("my_svm_model.xml"); + @endcode + In order to make this method work, the derived class must overwrite + Algorithm::read(const FileNode& fn). + */ + template + static Ptr<_Tp> load(const String &filename, + const String &objname = String()) { + FileStorage fs(filename, FileStorage::READ); + CV_Assert(fs.isOpened()); + FileNode fn = objname.empty() ? fs.getFirstTopLevelNode() : fs[objname]; + if (fn.empty()) + return Ptr<_Tp>(); + Ptr<_Tp> obj = _Tp::create(); + obj->read(fn); + return !obj->empty() ? obj : Ptr<_Tp>(); + } + + /** @brief Loads algorithm from a String + + @param strModel The string variable containing the model you want to load. + @param objname The optional name of the node to read (if empty, the first + top-level node will be used) + + This is static template method of Algorithm. It's usage is following (in the + case of SVM): + @code + Ptr svm = Algorithm::loadFromString(myStringModel); + @endcode + */ + template + static Ptr<_Tp> loadFromString(const String &strModel, + const String &objname = String()) { + FileStorage fs(strModel, FileStorage::READ + FileStorage::MEMORY); + FileNode fn = objname.empty() ? fs.getFirstTopLevelNode() : fs[objname]; + Ptr<_Tp> obj = _Tp::create(); + obj->read(fn); + return !obj->empty() ? obj : Ptr<_Tp>(); + } + + /** Saves the algorithm to a file. + In order to make this method work, the derived class must implement + Algorithm::write(FileStorage& fs). */ + CV_WRAP virtual void save(const String &filename) const; + + /** Returns the algorithm string identifier. + This string is used as top level xml/yml node tag when the object is saved to + a file or string. */ + CV_WRAP virtual String getDefaultName() const; + +protected: + void writeFormat(FileStorage &fs) const; +}; + +enum struct Param { + INT = 0, + BOOLEAN = 1, + REAL = 2, + STRING = 3, + MAT = 4, + MAT_VECTOR = 5, + ALGORITHM = 6, + FLOAT = 7, + UNSIGNED_INT = 8, + UINT64 = 9, + UCHAR = 11, + SCALAR = 12 +}; + +template <> struct ParamType { + typedef bool const_param_type; + typedef bool member_type; + + static const Param type = Param::BOOLEAN; +}; + +template <> struct ParamType { + typedef int const_param_type; + typedef int member_type; + + static const Param type = Param::INT; +}; + +template <> struct ParamType { + typedef double const_param_type; + typedef double member_type; + + static const Param type = Param::REAL; +}; + +template <> struct ParamType { + typedef const String &const_param_type; + typedef String member_type; + + static const Param type = Param::STRING; +}; + +template <> struct ParamType { + typedef const Mat &const_param_type; + typedef Mat member_type; + + static const Param type = Param::MAT; +}; + +template <> struct ParamType> { + typedef const std::vector &const_param_type; + typedef std::vector member_type; + + static const Param type = Param::MAT_VECTOR; +}; + +template <> struct ParamType { + typedef const Ptr &const_param_type; + typedef Ptr member_type; + + static const Param type = Param::ALGORITHM; +}; + +template <> struct ParamType { + typedef float const_param_type; + typedef float member_type; + + static const Param type = Param::FLOAT; +}; + +template <> struct ParamType { + typedef unsigned const_param_type; + typedef unsigned member_type; + + static const Param type = Param::UNSIGNED_INT; +}; + +template <> struct ParamType { + typedef uint64 const_param_type; + typedef uint64 member_type; + + static const Param type = Param::UINT64; +}; + +template <> struct ParamType { + typedef uchar const_param_type; + typedef uchar member_type; + + static const Param type = Param::UCHAR; +}; + +template <> struct ParamType { + typedef const Scalar &const_param_type; + typedef Scalar member_type; + + static const Param type = Param::SCALAR; +}; + +template +struct ParamType<_Tp, typename std::enable_if::value>::type> { + typedef typename std::underlying_type<_Tp>::type const_param_type; + typedef typename std::underlying_type<_Tp>::type member_type; + + static const Param type = Param::INT; +}; + +//! @} core_basic + +} // namespace cv + +#include "opencv2/core/cvstd.inl.hpp" +#include "opencv2/core/operations.hpp" +#include "opencv2/core/optim.hpp" +#include "opencv2/core/utility.hpp" + +#endif /*OPENCV_CORE_HPP*/ diff --git a/third-party/include/opencv2/core/affine.hpp b/third-party/include/opencv2/core/affine.hpp new file mode 100644 index 0000000000..f4aabb409d --- /dev/null +++ b/third-party/include/opencv2/core/affine.hpp @@ -0,0 +1,676 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this +license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright +notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote +products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" +and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are +disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any +direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_AFFINE3_HPP +#define OPENCV_CORE_AFFINE3_HPP + +#ifdef __cplusplus + +#include + +namespace cv { + +//! @addtogroup core_eigen +//! @{ + +/** @brief Affine transform + * + * It represents a 4x4 homogeneous transformation matrix \f$T\f$ + * + * \f[T = + * \begin{bmatrix} + * R & t\\ + * 0 & 1\\ + * \end{bmatrix} + * \f] + * + * where \f$R\f$ is a 3x3 rotation matrix and \f$t\f$ is a 3x1 translation + * vector. + * + * You can specify \f$R\f$ either by a 3x3 rotation matrix or by a 3x1 rotation + * vector, which is converted to a 3x3 rotation matrix by the Rodrigues formula. + * + * To construct a matrix \f$T\f$ representing first rotation around the axis + * \f$r\f$ with rotation angle \f$|r|\f$ in radian (right hand rule) and then + * translation by the vector \f$t\f$, you can use + * + * @code + * cv::Vec3f r, t; + * cv::Affine3f T(r, t); + * @endcode + * + * If you already have the rotation matrix \f$R\f$, then you can use + * + * @code + * cv::Matx33f R; + * cv::Affine3f T(R, t); + * @endcode + * + * To extract the rotation matrix \f$R\f$ from \f$T\f$, use + * + * @code + * cv::Matx33f R = T.rotation(); + * @endcode + * + * To extract the translation vector \f$t\f$ from \f$T\f$, use + * + * @code + * cv::Vec3f t = T.translation(); + * @endcode + * + * To extract the rotation vector \f$r\f$ from \f$T\f$, use + * + * @code + * cv::Vec3f r = T.rvec(); + * @endcode + * + * Note that since the mapping from rotation vectors to rotation matrices + * is many to one. The returned rotation vector is not necessarily the one + * you used before to set the matrix. + * + * If you have two transformations \f$T = T_1 * T_2\f$, use + * + * @code + * cv::Affine3f T, T1, T2; + * T = T2.concatenate(T1); + * @endcode + * + * To get the inverse transform of \f$T\f$, use + * + * @code + * cv::Affine3f T, T_inv; + * T_inv = T.inv(); + * @endcode + * + */ +template class Affine3 { +public: + typedef T float_type; + typedef Matx Mat3; + typedef Matx Mat4; + typedef Vec Vec3; + + //! Default constructor. It represents a 4x4 identity matrix. + Affine3(); + + //! Augmented affine matrix + Affine3(const Mat4 &affine); + + /** + * The resulting 4x4 matrix is + * + * \f[ + * \begin{bmatrix} + * R & t\\ + * 0 & 1\\ + * \end{bmatrix} + * \f] + * + * @param R 3x3 rotation matrix. + * @param t 3x1 translation vector. + */ + Affine3(const Mat3 &R, const Vec3 &t = Vec3::all(0)); + + /** + * Rodrigues vector. + * + * The last row of the current matrix is set to [0,0,0,1]. + * + * @param rvec 3x1 rotation vector. Its direction indicates the rotation axis + * and its length indicates the rotation angle in radian (using right hand + * rule). + * @param t 3x1 translation vector. + */ + Affine3(const Vec3 &rvec, const Vec3 &t = Vec3::all(0)); + + /** + * Combines all constructors above. Supports 4x4, 3x4, 3x3, 1x3, 3x1 sizes of + * data matrix. + * + * The last row of the current matrix is set to [0,0,0,1] when data is not + * 4x4. + * + * @param data 1-channel matrix. + * when it is 4x4, it is copied to the current matrix and t is not + * used. When it is 3x4, it is copied to the upper part 3x4 of the current + * matrix and t is not used. When it is 3x3, it is copied to the upper left + * 3x3 part of the current matrix. When it is 3x1 or 1x3, it is treated as a + * rotation vector and the Rodrigues formula is used to compute a 3x3 rotation + * matrix. + * @param t 3x1 translation vector. It is used only when data is neither 4x4 + * nor 3x4. + */ + explicit Affine3(const Mat &data, const Vec3 &t = Vec3::all(0)); + + //! From 16-element array + explicit Affine3(const float_type *vals); + + //! Create an 4x4 identity transform + static Affine3 Identity(); + + /** + * Rotation matrix. + * + * Copy the rotation matrix to the upper left 3x3 part of the current matrix. + * The remaining elements of the current matrix are not changed. + * + * @param R 3x3 rotation matrix. + * + */ + void rotation(const Mat3 &R); + + /** + * Rodrigues vector. + * + * It sets the upper left 3x3 part of the matrix. The remaining part is + * unaffected. + * + * @param rvec 3x1 rotation vector. The direction indicates the rotation axis + * and its length indicates the rotation angle in radian (using the right + * thumb convention). + */ + void rotation(const Vec3 &rvec); + + /** + * Combines rotation methods above. Supports 3x3, 1x3, 3x1 sizes of data + * matrix. + * + * It sets the upper left 3x3 part of the matrix. The remaining part is + * unaffected. + * + * @param data 1-channel matrix. + * When it is a 3x3 matrix, it sets the upper left 3x3 part of the + * current matrix. When it is a 1x3 or 3x1 matrix, it is used as a rotation + * vector. The Rodrigues formula is used to compute the rotation matrix and + * sets the upper left 3x3 part of the current matrix. + */ + void rotation(const Mat &data); + + /** + * Copy the 3x3 matrix L to the upper left part of the current matrix + * + * It sets the upper left 3x3 part of the matrix. The remaining part is + * unaffected. + * + * @param L 3x3 matrix. + */ + void linear(const Mat3 &L); + + /** + * Copy t to the first three elements of the last column of the current matrix + * + * It sets the upper right 3x1 part of the matrix. The remaining part is + * unaffected. + * + * @param t 3x1 translation vector. + */ + void translation(const Vec3 &t); + + //! @return the upper left 3x3 part + Mat3 rotation() const; + + //! @return the upper left 3x3 part + Mat3 linear() const; + + //! @return the upper right 3x1 part + Vec3 translation() const; + + //! Rodrigues vector. + //! @return a vector representing the upper left 3x3 rotation matrix of the + //! current matrix. + //! @warning Since the mapping between rotation vectors and rotation matrices + //! is many to one, + //! this function returns only one rotation vector that represents + //! the current rotation matrix, which is not necessarily the same + //! one set by `rotation(const Vec3& rvec)`. + Vec3 rvec() const; + + //! @return the inverse of the current matrix. + Affine3 inv(int method = cv::DECOMP_SVD) const; + + //! a.rotate(R) is equivalent to Affine(R, 0) * a; + Affine3 rotate(const Mat3 &R) const; + + //! a.rotate(rvec) is equivalent to Affine(rvec, 0) * a; + Affine3 rotate(const Vec3 &rvec) const; + + //! a.translate(t) is equivalent to Affine(E, t) * a, where E is an identity + //! matrix + Affine3 translate(const Vec3 &t) const; + + //! a.concatenate(affine) is equivalent to affine * a; + Affine3 concatenate(const Affine3 &affine) const; + + template operator Affine3() const; + + template Affine3 cast() const; + + Mat4 matrix; + +#if defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H + Affine3( + const Eigen::Transform &affine); + Affine3(const Eigen::Transform &affine); + operator Eigen::Transform() const; + operator Eigen::Transform() const; +#endif +}; + +template +static Affine3 operator*(const Affine3 &affine1, + const Affine3 &affine2); + +//! V is a 3-element vector with member fields x, y and z +template +static V operator*(const Affine3 &affine, const V &vector); + +typedef Affine3 Affine3f; +typedef Affine3 Affine3d; + +static Vec3f operator*(const Affine3f &affine, const Vec3f &vector); +static Vec3d operator*(const Affine3d &affine, const Vec3d &vector); + +template class DataType> { +public: + typedef Affine3<_Tp> value_type; + typedef Affine3::work_type> work_type; + typedef _Tp channel_type; + + enum { + generic_type = 0, + channels = 16, + fmt = traits::SafeFmt::fmt + ((channels - 1) << 8) +#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED + , + depth = DataType::depth, + type = CV_MAKETYPE(depth, channels) +#endif + }; + + typedef Vec vec_type; +}; + +namespace traits { +template struct Depth> { + enum { value = Depth<_Tp>::value }; +}; +template struct Type> { + enum { value = CV_MAKETYPE(Depth<_Tp>::value, 16) }; +}; +} // namespace traits + +//! @} core + +} // namespace cv + +//! @cond IGNORED + +/////////////////////////////////////////////////////////////////////////////////// +// Implementation + +template inline cv::Affine3::Affine3() : matrix(Mat4::eye()) {} + +template +inline cv::Affine3::Affine3(const Mat4 &affine) : matrix(affine) {} + +template +inline cv::Affine3::Affine3(const Mat3 &R, const Vec3 &t) { + rotation(R); + translation(t); + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template +inline cv::Affine3::Affine3(const Vec3 &_rvec, const Vec3 &t) { + rotation(_rvec); + translation(t); + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template +inline cv::Affine3::Affine3(const cv::Mat &data, const Vec3 &t) { + CV_Assert(data.type() == cv::traits::Type::value); + CV_Assert(data.channels() == 1); + + if (data.cols == 4 && data.rows == 4) { + data.copyTo(matrix); + return; + } else if (data.cols == 4 && data.rows == 3) { + rotation(data(Rect(0, 0, 3, 3))); + translation(data(Rect(3, 0, 1, 3))); + } else { + rotation(data); + translation(t); + } + + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template +inline cv::Affine3::Affine3(const float_type *vals) : matrix(vals) {} + +template inline cv::Affine3 cv::Affine3::Identity() { + return Affine3(cv::Affine3::Mat4::eye()); +} + +template inline void cv::Affine3::rotation(const Mat3 &R) { + linear(R); +} + +template inline void cv::Affine3::rotation(const Vec3 &_rvec) { + double theta = norm(_rvec); + + if (theta < DBL_EPSILON) + rotation(Mat3::eye()); + else { + double c = std::cos(theta); + double s = std::sin(theta); + double c1 = 1. - c; + double itheta = (theta != 0) ? 1. / theta : 0.; + + Point3_ r = _rvec * itheta; + + Mat3 rrt(r.x * r.x, r.x * r.y, r.x * r.z, r.x * r.y, r.y * r.y, r.y * r.z, + r.x * r.z, r.y * r.z, r.z * r.z); + Mat3 r_x(0, -r.z, r.y, r.z, 0, -r.x, -r.y, r.x, 0); + + // R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x] + // where [r_x] is [0 -rz ry; rz 0 -rx; -ry rx 0] + Mat3 R = c * Mat3::eye() + c1 * rrt + s * r_x; + + rotation(R); + } +} + +// Combines rotation methods above. Supports 3x3, 1x3, 3x1 sizes of data matrix; +template +inline void cv::Affine3::rotation(const cv::Mat &data) { + CV_Assert(data.type() == cv::traits::Type::value); + CV_Assert(data.channels() == 1); + + if (data.cols == 3 && data.rows == 3) { + Mat3 R; + data.copyTo(R); + rotation(R); + } else if ((data.cols == 3 && data.rows == 1) || + (data.cols == 1 && data.rows == 3)) { + Vec3 _rvec; + data.reshape(1, 3).copyTo(_rvec); + rotation(_rvec); + } else + CV_Error(Error::StsError, "Input matrix can only be 3x3, 1x3 or 3x1"); +} + +template inline void cv::Affine3::linear(const Mat3 &L) { + matrix.val[0] = L.val[0]; + matrix.val[1] = L.val[1]; + matrix.val[2] = L.val[2]; + matrix.val[4] = L.val[3]; + matrix.val[5] = L.val[4]; + matrix.val[6] = L.val[5]; + matrix.val[8] = L.val[6]; + matrix.val[9] = L.val[7]; + matrix.val[10] = L.val[8]; +} + +template inline void cv::Affine3::translation(const Vec3 &t) { + matrix.val[3] = t[0]; + matrix.val[7] = t[1]; + matrix.val[11] = t[2]; +} + +template +inline typename cv::Affine3::Mat3 cv::Affine3::rotation() const { + return linear(); +} + +template +inline typename cv::Affine3::Mat3 cv::Affine3::linear() const { + typename cv::Affine3::Mat3 R; + R.val[0] = matrix.val[0]; + R.val[1] = matrix.val[1]; + R.val[2] = matrix.val[2]; + R.val[3] = matrix.val[4]; + R.val[4] = matrix.val[5]; + R.val[5] = matrix.val[6]; + R.val[6] = matrix.val[8]; + R.val[7] = matrix.val[9]; + R.val[8] = matrix.val[10]; + return R; +} + +template +inline typename cv::Affine3::Vec3 cv::Affine3::translation() const { + return Vec3(matrix.val[3], matrix.val[7], matrix.val[11]); +} + +template +inline typename cv::Affine3::Vec3 cv::Affine3::rvec() const { + cv::Vec3d w; + cv::Matx33d u, vt, R = rotation(); + cv::SVD::compute(R, w, u, vt, cv::SVD::FULL_UV + cv::SVD::MODIFY_A); + R = u * vt; + + double rx = R.val[7] - R.val[5]; + double ry = R.val[2] - R.val[6]; + double rz = R.val[3] - R.val[1]; + + double s = std::sqrt((rx * rx + ry * ry + rz * rz) * 0.25); + double c = (R.val[0] + R.val[4] + R.val[8] - 1) * 0.5; + c = c > 1.0 ? 1.0 : c < -1.0 ? -1.0 : c; + double theta = std::acos(c); + + if (s < 1e-5) { + if (c > 0) + rx = ry = rz = 0; + else { + double t; + t = (R.val[0] + 1) * 0.5; + rx = std::sqrt(std::max(t, 0.0)); + t = (R.val[4] + 1) * 0.5; + ry = std::sqrt(std::max(t, 0.0)) * (R.val[1] < 0 ? -1.0 : 1.0); + t = (R.val[8] + 1) * 0.5; + rz = std::sqrt(std::max(t, 0.0)) * (R.val[2] < 0 ? -1.0 : 1.0); + + if (fabs(rx) < fabs(ry) && fabs(rx) < fabs(rz) && + (R.val[5] > 0) != (ry * rz > 0)) + rz = -rz; + theta /= std::sqrt(rx * rx + ry * ry + rz * rz); + rx *= theta; + ry *= theta; + rz *= theta; + } + } else { + double vth = 1 / (2 * s); + vth *= theta; + rx *= vth; + ry *= vth; + rz *= vth; + } + + return cv::Vec3d(rx, ry, rz); +} + +template +inline cv::Affine3 cv::Affine3::inv(int method) const { + return matrix.inv(method); +} + +template +inline cv::Affine3 cv::Affine3::rotate(const Mat3 &R) const { + Mat3 Lc = linear(); + Vec3 tc = translation(); + Mat4 result; + result.val[12] = result.val[13] = result.val[14] = 0; + result.val[15] = 1; + + for (int j = 0; j < 3; ++j) { + for (int i = 0; i < 3; ++i) { + float_type value = 0; + for (int k = 0; k < 3; ++k) + value += R(j, k) * Lc(k, i); + result(j, i) = value; + } + + result(j, 3) = R.row(j).dot(tc.t()); + } + return result; +} + +template +inline cv::Affine3 cv::Affine3::rotate(const Vec3 &_rvec) const { + return rotate(Affine3f(_rvec).rotation()); +} + +template +inline cv::Affine3 cv::Affine3::translate(const Vec3 &t) const { + Mat4 m = matrix; + m.val[3] += t[0]; + m.val[7] += t[1]; + m.val[11] += t[2]; + return m; +} + +template +inline cv::Affine3 +cv::Affine3::concatenate(const Affine3 &affine) const { + return (*this).rotate(affine.rotation()).translate(affine.translation()); +} + +template +template +inline cv::Affine3::operator Affine3() const { + return Affine3(matrix); +} + +template +template +inline cv::Affine3 cv::Affine3::cast() const { + return Affine3(matrix); +} + +template +inline cv::Affine3 cv::operator*(const cv::Affine3 &affine1, + const cv::Affine3 &affine2) { + return affine2.concatenate(affine1); +} + +template +inline V cv::operator*(const cv::Affine3 &affine, const V &v) { + const typename Affine3::Mat4 &m = affine.matrix; + + V r; + r.x = m.val[0] * v.x + m.val[1] * v.y + m.val[2] * v.z + m.val[3]; + r.y = m.val[4] * v.x + m.val[5] * v.y + m.val[6] * v.z + m.val[7]; + r.z = m.val[8] * v.x + m.val[9] * v.y + m.val[10] * v.z + m.val[11]; + return r; +} + +static inline cv::Vec3f cv::operator*(const cv::Affine3f &affine, + const cv::Vec3f &v) { + const cv::Matx44f &m = affine.matrix; + cv::Vec3f r; + r.val[0] = m.val[0] * v[0] + m.val[1] * v[1] + m.val[2] * v[2] + m.val[3]; + r.val[1] = m.val[4] * v[0] + m.val[5] * v[1] + m.val[6] * v[2] + m.val[7]; + r.val[2] = m.val[8] * v[0] + m.val[9] * v[1] + m.val[10] * v[2] + m.val[11]; + return r; +} + +static inline cv::Vec3d cv::operator*(const cv::Affine3d &affine, + const cv::Vec3d &v) { + const cv::Matx44d &m = affine.matrix; + cv::Vec3d r; + r.val[0] = m.val[0] * v[0] + m.val[1] * v[1] + m.val[2] * v[2] + m.val[3]; + r.val[1] = m.val[4] * v[0] + m.val[5] * v[1] + m.val[6] * v[2] + m.val[7]; + r.val[2] = m.val[8] * v[0] + m.val[9] * v[1] + m.val[10] * v[2] + m.val[11]; + return r; +} + +#if defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H + +template +inline cv::Affine3::Affine3( + const Eigen::Transform &affine) { + cv::Mat(4, 4, cv::traits::Type::value, affine.matrix().data()) + .copyTo(matrix); +} + +template +inline cv::Affine3::Affine3( + const Eigen::Transform &affine) { + Eigen::Transform a = affine; + cv::Mat(4, 4, cv::traits::Type::value, a.matrix().data()).copyTo(matrix); +} + +template +inline cv::Affine3::operator Eigen::Transform() const { + Eigen::Transform r; + cv::Mat hdr(4, 4, cv::traits::Type::value, r.matrix().data()); + cv::Mat(matrix, false).copyTo(hdr); + return r; +} + +template +inline cv::Affine3::operator Eigen::Transform() const { + return this + ->operator Eigen::Transform(); +} + +#endif /* defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H */ + +//! @endcond + +#endif /* __cplusplus */ + +#endif /* OPENCV_CORE_AFFINE3_HPP */ diff --git a/third-party/include/opencv2/core/async.hpp b/third-party/include/opencv2/core/async.hpp new file mode 100644 index 0000000000..9c48f1625a --- /dev/null +++ b/third-party/include/opencv2/core/async.hpp @@ -0,0 +1,107 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_ASYNC_HPP +#define OPENCV_CORE_ASYNC_HPP + +#include + +// #include +#include + +namespace cv { + +/** @addtogroup core_async + +@{ +*/ + +/** @brief Returns result of asynchronous operations + +Object has attached asynchronous state. +Assignment operator doesn't clone asynchronous state (it is shared between all +instances). + +Result can be fetched via get() method only once. + +*/ +class CV_EXPORTS_W AsyncArray { +public: + ~AsyncArray() CV_NOEXCEPT; + CV_WRAP AsyncArray() CV_NOEXCEPT; + AsyncArray(const AsyncArray &o) CV_NOEXCEPT; + AsyncArray &operator=(const AsyncArray &o) CV_NOEXCEPT; + CV_WRAP void release() CV_NOEXCEPT; + + /** Fetch the result. + @param[out] dst destination array + + Waits for result until container has valid result. + Throws exception if exception was stored as a result. + + Throws exception on invalid container state. + + @note Result or stored exception can be fetched only once. + */ + CV_WRAP void get(OutputArray dst) const; + + /** Retrieving the result with timeout + @param[out] dst destination array + @param[in] timeoutNs timeout in nanoseconds, -1 for infinite wait + + @returns true if result is ready, false if the timeout has expired + + @note Result or stored exception can be fetched only once. + */ + bool get(OutputArray dst, int64 timeoutNs) const; + + CV_WRAP inline bool get(OutputArray dst, double timeoutNs) const { + return get(dst, (int64)timeoutNs); + } + + bool wait_for(int64 timeoutNs) const; + + CV_WRAP inline bool wait_for(double timeoutNs) const { + return wait_for((int64)timeoutNs); + } + + CV_WRAP bool valid() const CV_NOEXCEPT; + + inline AsyncArray(AsyncArray &&o) { + p = o.p; + o.p = NULL; + } + inline AsyncArray &operator=(AsyncArray &&o) CV_NOEXCEPT { + std::swap(p, o.p); + return *this; + } + + template + inline bool get(OutputArray dst, + const std::chrono::duration<_Rep, _Period> &timeout) { + return get(dst, (int64)(std::chrono::nanoseconds(timeout).count())); + } + + template + inline bool wait_for(const std::chrono::duration<_Rep, _Period> &timeout) { + return wait_for((int64)(std::chrono::nanoseconds(timeout).count())); + } + +#if 0 + std::future getFutureMat() const; + std::future getFutureUMat() const; +#endif + + // PImpl + struct Impl; + friend struct Impl; + inline void *_getImpl() const CV_NOEXCEPT { return p; } + +protected: + Impl *p; +}; + +//! @} +} // namespace cv +#endif // OPENCV_CORE_ASYNC_HPP diff --git a/third-party/include/opencv2/core/base.hpp b/third-party/include/opencv2/core/base.hpp new file mode 100644 index 0000000000..3dfa243df6 --- /dev/null +++ b/third-party/include/opencv2/core/base.hpp @@ -0,0 +1,735 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this +license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2014, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright +notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote +products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" +and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are +disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any +direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_BASE_HPP +#define OPENCV_CORE_BASE_HPP + +#ifndef __cplusplus +#error base.hpp header must be compiled as C++ +#endif + +#include "opencv2/opencv_modules.hpp" + +#include +#include + +#include "opencv2/core/cvdef.h" +#include "opencv2/core/cvstd.hpp" + +namespace cv { + +//! @addtogroup core_utils +//! @{ + +namespace Error { +//! error codes +enum Code { + StsOk = 0, //!< everything is ok + StsBackTrace = -1, //!< pseudo error for back trace + StsError = -2, //!< unknown /unspecified error + StsInternal = -3, //!< internal error (bad state) + StsNoMem = -4, //!< insufficient memory + StsBadArg = -5, //!< function arg/param is bad + StsBadFunc = -6, //!< unsupported function + StsNoConv = -7, //!< iteration didn't converge + StsAutoTrace = -8, //!< tracing + HeaderIsNull = -9, //!< image header is NULL + BadImageSize = -10, //!< image size is invalid + BadOffset = -11, //!< offset is invalid + BadDataPtr = -12, //!< + BadStep = -13, //!< image step is wrong, this may happen for a non-continuous + //!< matrix. + BadModelOrChSeq = -14, //!< + BadNumChannels = -15, //!< bad number of channels, for example, some functions + //!< accept only single channel matrices. + BadNumChannel1U = -16, //!< + BadDepth = -17, //!< input image depth is not supported by the function + BadAlphaChannel = -18, //!< + BadOrder = -19, //!< number of dimensions is out of range + BadOrigin = -20, //!< incorrect input origin + BadAlign = -21, //!< incorrect input align + BadCallBack = -22, //!< + BadTileSize = -23, //!< + BadCOI = -24, //!< input COI is not supported + BadROISize = -25, //!< incorrect input roi + MaskIsTiled = -26, //!< + StsNullPtr = -27, //!< null pointer + StsVecLengthErr = -28, //!< incorrect vector length + StsFilterStructContentErr = -29, //!< incorrect filter structure content + StsKernelStructContentErr = -30, //!< incorrect transform kernel content + StsFilterOffsetErr = -31, //!< incorrect filter offset value + StsBadSize = -201, //!< the input/output structure size is incorrect + StsDivByZero = -202, //!< division by zero + StsInplaceNotSupported = -203, //!< in-place operation is not supported + StsObjectNotFound = -204, //!< request can't be completed + StsUnmatchedFormats = -205, //!< formats of input/output arrays differ + StsBadFlag = -206, //!< flag is wrong or not supported + StsBadPoint = -207, //!< bad CvPoint + StsBadMask = -208, //!< bad format of mask (neither 8uC1 nor 8sC1) + StsUnmatchedSizes = -209, //!< sizes of input/output structures do not match + StsUnsupportedFormat = + -210, //!< the data format/type is not supported by the function + StsOutOfRange = -211, //!< some of parameters are out of range + StsParseError = -212, //!< invalid syntax/structure of the parsed file + StsNotImplemented = + -213, //!< the requested function/feature is not implemented + StsBadMemBlock = -214, //!< an allocated block has been corrupted + StsAssert = -215, //!< assertion failed + GpuNotSupported = -216, //!< no CUDA support + GpuApiCallError = -217, //!< GPU API call error + OpenGlNotSupported = -218, //!< no OpenGL support + OpenGlApiCallError = -219, //!< OpenGL API call error + OpenCLApiCallError = -220, //!< OpenCL API call error + OpenCLDoubleNotSupported = -221, + OpenCLInitError = -222, //!< OpenCL initialization error + OpenCLNoAMDBlasFft = -223 +}; +} // namespace Error + +//! @} core_utils + +//! @addtogroup core_array +//! @{ + +//! matrix decomposition types +enum DecompTypes { + /** Gaussian elimination with the optimal pivot element chosen. */ + DECOMP_LU = 0, + /** singular value decomposition (SVD) method; the system can be over-defined + and/or the matrix src1 can be singular */ + DECOMP_SVD = 1, + /** eigenvalue decomposition; the matrix src1 must be symmetrical */ + DECOMP_EIG = 2, + /** Cholesky \f$LL^T\f$ factorization; the matrix src1 must be symmetrical and + positively defined */ + DECOMP_CHOLESKY = 3, + /** QR factorization; the system can be over-defined and/or the matrix src1 + can be singular */ + DECOMP_QR = 4, + /** while all the previous flags are mutually exclusive, this flag can be used + together with any of the previous; it means that the normal equations + \f$\texttt{src1}^T\cdot\texttt{src1}\cdot\texttt{dst}=\texttt{src1}^T\texttt{src2}\f$ + are solved instead of the original system + \f$\texttt{src1}\cdot\texttt{dst}=\texttt{src2}\f$ */ + DECOMP_NORMAL = 16 +}; + +/** norm types + +src1 and src2 denote input arrays. +*/ + +enum NormTypes { + /** + \f[ + norm = \forkthree + {\|\texttt{src1}\|_{L_{\infty}} = \max _I | \texttt{src1} (I)|}{if + \(\texttt{normType} = \texttt{NORM_INF}\) } + {\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} = \max _I | \texttt{src1} (I) - + \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) } + {\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} + }{\|\texttt{src2}\|_{L_{\infty}} }}{if \(\texttt{normType} = + \texttt{NORM_RELATIVE | NORM_INF}\) } + \f] + */ + NORM_INF = 1, + /** + \f[ + norm = \forkthree + {\| \texttt{src1} \| _{L_1} = \sum _I | \texttt{src1} (I)|}{if + \(\texttt{normType} = \texttt{NORM_L1}\)} { \| \texttt{src1} - \texttt{src2} + \| _{L_1} = \sum _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if + \(\texttt{normType} = \texttt{NORM_L1}\) } { + \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if + \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L1}\) } + \f]*/ + NORM_L1 = 2, + /** + \f[ + norm = \forkthree + { \| \texttt{src1} \| _{L_2} = \sqrt{\sum_I \texttt{src1}(I)^2} }{if + \(\texttt{normType} = \texttt{NORM_L2}\) } { \| \texttt{src1} - \texttt{src2} + \| _{L_2} = \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if + \(\texttt{normType} = \texttt{NORM_L2}\) } { + \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if + \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L2}\) } + \f] + */ + NORM_L2 = 4, + /** + \f[ + norm = \forkthree + { \| \texttt{src1} \| _{L_2} ^{2} = \sum_I \texttt{src1}(I)^2} {if + \(\texttt{normType} = \texttt{NORM_L2SQR}\)} { \| \texttt{src1} - + \texttt{src2} \| _{L_2} ^{2} = \sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2 + }{if \(\texttt{normType} = \texttt{NORM_L2SQR}\) } { + \left(\frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} + }{\|\texttt{src2}\|_{L_2}}\right)^2 }{if \(\texttt{normType} = + \texttt{NORM_RELATIVE | NORM_L2SQR}\) } + \f] + */ + NORM_L2SQR = 5, + /** + In the case of one input array, calculates the Hamming distance of the array + from zero, In the case of two input arrays, calculates the Hamming distance + between the arrays. + */ + NORM_HAMMING = 6, + /** + Similar to NORM_HAMMING, but in the calculation, each two bits of the input + sequence will be added and treated as a single bit to be used in the same + calculation as NORM_HAMMING. + */ + NORM_HAMMING2 = 7, + NORM_TYPE_MASK = + 7, //!< bit-mask which can be used to separate norm type from norm flags + NORM_RELATIVE = 8, //!< flag + NORM_MINMAX = 32 //!< flag +}; + +//! comparison types +enum CmpTypes { + CMP_EQ = 0, //!< src1 is equal to src2. + CMP_GT = 1, //!< src1 is greater than src2. + CMP_GE = 2, //!< src1 is greater than or equal to src2. + CMP_LT = 3, //!< src1 is less than src2. + CMP_LE = 4, //!< src1 is less than or equal to src2. + CMP_NE = 5 //!< src1 is unequal to src2. +}; + +//! generalized matrix multiplication flags +enum GemmFlags { + GEMM_1_T = 1, //!< transposes src1 + GEMM_2_T = 2, //!< transposes src2 + GEMM_3_T = 4 //!< transposes src3 +}; + +enum DftFlags { + /** performs an inverse 1D or 2D transform instead of the default forward + transform. */ + DFT_INVERSE = 1, + /** scales the result: divide it by the number of array elements. Normally, it + is combined with DFT_INVERSE. */ + DFT_SCALE = 2, + /** performs a forward or inverse transform of every individual row of the + input matrix; this flag enables you to transform multiple vectors + simultaneously and can be used to decrease the overhead (which is sometimes + several times larger than the processing itself) to perform 3D and + higher-dimensional transformations and so forth.*/ + DFT_ROWS = 4, + /** performs a forward transformation of 1D or 2D real array; the result, + though being a complex array, has complex-conjugate symmetry (*CCS*, see + the function description below for details), and such an array can be + packed into a real array of the same size as input, which is the fastest + option and which is what the function does by default; however, you may + wish to get a full complex array (for simpler spectrum analysis, and so on) + - pass the flag to enable the function to produce a full-size complex + output array. */ + DFT_COMPLEX_OUTPUT = 16, + /** performs an inverse transformation of a 1D or 2D complex array; the + result is normally a complex array of the same size, however, if the input + array has conjugate-complex symmetry (for example, it is a result of + forward transformation with DFT_COMPLEX_OUTPUT flag), the output is a real + array; while the function itself does not check whether the input is + symmetrical or not, you can pass the flag and then the function will assume + the symmetry and produce the real output array (note that when the input is + packed into a real array and inverse transformation is executed, the + function treats the input as a packed complex-conjugate symmetrical array, + and the output will also be a real array). */ + DFT_REAL_OUTPUT = 32, + /** specifies that input is complex input. If this flag is set, the input must + have 2 channels. On the other hand, for backwards compatibility reason, if + input has 2 channels, input is already considered complex. */ + DFT_COMPLEX_INPUT = 64, + /** performs an inverse 1D or 2D transform instead of the default forward + transform. */ + DCT_INVERSE = DFT_INVERSE, + /** performs a forward or inverse transform of every individual row of the + input matrix. This flag enables you to transform multiple vectors + simultaneously and can be used to decrease the overhead (which is sometimes + several times larger than the processing itself) to perform 3D and + higher-dimensional transforms and so forth.*/ + DCT_ROWS = DFT_ROWS +}; + +//! Various border types, image boundaries are denoted with `|` +//! @see borderInterpolate, copyMakeBorder +enum BorderTypes { + BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i` + BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh` + BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb` + BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg` + BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba` + BORDER_TRANSPARENT = + 5, //!< `uvwxyz|abcdefgh|ijklmno` - Treats outliers as transparent. + + BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101 + BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101 + BORDER_ISOLATED = 16 //!< Interpolation restricted within the ROI boundaries. +}; + +//! @} core_array + +//! @addtogroup core_utils +//! @{ + +/*! @brief Signals an error and raises the exception. + +By default the function prints information about the error to stderr, +then it either stops if setBreakOnError() had been called before or raises the +exception. It is possible to alternate error processing by using +redirectError(). +@param code - error code (Error::Code) +@param err - error description +@param func - function name. Available only when the compiler supports getting +it +@param file - source file name where the error has occurred +@param line - line number in the source file where the error has occurred +@see CV_Error, CV_Error_, CV_Assert, CV_DbgAssert + */ +CV_EXPORTS CV_NORETURN void error(int code, const String &err, const char *func, + const char *file, int line); + +/*! @brief Signals an error and terminate application. + +By default the function prints information about the error to stderr, then it +terminates application with std::terminate. The function is designed for +invariants check in functions and methods with noexcept attribute. +@param code - error code (Error::Code) +@param err - error description +@param func - function name. Available only when the compiler supports getting +it +@param file - source file name where the error has occurred +@param line - line number in the source file where the error has occurred +@see CV_AssertTerminate + */ +CV_EXPORTS CV_NORETURN void terminate(int code, const String &err, + const char *func, const char *file, + int line) CV_NOEXCEPT; + +#ifdef CV_STATIC_ANALYSIS + +// In practice, some macro are not processed correctly (noreturn is not +// detected). We need to use simplified definition for them. +#define CV_Error(code, msg) \ + do { \ + (void)(code); \ + (void)(msg); \ + abort(); \ + } while (0) +#define CV_Error_(code, args) \ + do { \ + (void)(code); \ + (void)(cv::format args); \ + abort(); \ + } while (0) +#define CV_Assert(expr) \ + do { \ + if (!(expr)) \ + abort(); \ + } while (0) + +#else // CV_STATIC_ANALYSIS + +/** @brief Call the error handler. + +Currently, the error handler prints the error code and the error message to the +standard error stream `stderr`. In the Debug configuration, it then provokes +memory access violation, so that the execution stack and all the parameters can +be analyzed by the debugger. In the Release configuration, the exception is +thrown. + +@param code one of Error::Code +@param msg error message +*/ +#define CV_Error(code, msg) cv::error(code, msg, CV_Func, __FILE__, __LINE__) + +/** @brief Call the error handler. + +This macro can be used to construct an error message on-fly to include some +dynamic information, for example: +@code + // note the extra parentheses around the formatted text message + CV_Error_(Error::StsOutOfRange, + ("the value at (%d, %d)=%g is out of range", badPt.x, badPt.y, badValue)); +@endcode +@param code one of Error::Code +@param args printf-like formatted error message in parentheses +*/ +#define CV_Error_(code, args) \ + cv::error(code, cv::format args, CV_Func, __FILE__, __LINE__) + +/** @brief Checks a condition at runtime and throws exception if it fails + +The macros CV_Assert (and CV_DbgAssert(expr)) evaluate the specified expression. +If it is 0, the macros raise an error (see cv::error). The macro CV_Assert +checks the condition in both Debug and Release configurations while CV_DbgAssert +is only retained in the Debug configuration. CV_AssertTerminate is analog of +CV_Assert for invariants check in functions with noexcept attribute. It does not +throw exception, but terminates the application. +*/ +#define CV_Assert(expr) \ + do { \ + if (!!(expr)) \ + ; \ + else \ + cv::error(cv::Error::StsAssert, #expr, CV_Func, __FILE__, __LINE__); \ + } while (0) +#define CV_AssertTerminate(expr) \ + do { \ + if (!!(expr)) \ + ; \ + else \ + cv::terminate(#expr, CV_Func, __FILE__, __LINE__); \ + } while (0) + +#endif // CV_STATIC_ANALYSIS + +//! @cond IGNORED +#if !defined(__OPENCV_BUILD) // TODO: backward compatibility only +#ifndef CV_ErrorNoReturn +#define CV_ErrorNoReturn CV_Error +#endif +#ifndef CV_ErrorNoReturn_ +#define CV_ErrorNoReturn_ CV_Error_ +#endif +#endif + +#define CV_Assert_1 CV_Assert +#define CV_Assert_2(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_1(__VA_ARGS__)) +#define CV_Assert_3(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_2(__VA_ARGS__)) +#define CV_Assert_4(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_3(__VA_ARGS__)) +#define CV_Assert_5(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_4(__VA_ARGS__)) +#define CV_Assert_6(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_5(__VA_ARGS__)) +#define CV_Assert_7(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_6(__VA_ARGS__)) +#define CV_Assert_8(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_7(__VA_ARGS__)) +#define CV_Assert_9(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_8(__VA_ARGS__)) +#define CV_Assert_10(expr, ...) \ + CV_Assert_1(expr); \ + __CV_EXPAND(CV_Assert_9(__VA_ARGS__)) + +#define CV_Assert_N(...) \ + do { \ + __CV_EXPAND( \ + __CV_CAT(CV_Assert_, __CV_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)); \ + } while (0) + +//! @endcond + +#if defined _DEBUG || defined CV_STATIC_ANALYSIS +#define CV_DbgAssert(expr) CV_Assert(expr) +#else +/** replaced with CV_Assert(expr) in Debug configuration */ +#define CV_DbgAssert(expr) +#endif + +/* + * Hamming distance functor - counts the bit differences between two strings - + * useful for the Brief descriptor bit count of A exclusive XOR'ed with B + */ +struct CV_EXPORTS Hamming { + static const NormTypes normType = NORM_HAMMING; + typedef unsigned char ValueType; + typedef int ResultType; + + /** this will count the bits in a ^ b + */ + ResultType operator()(const unsigned char *a, const unsigned char *b, + int size) const; +}; + +typedef Hamming HammingLUT; + +/////////////////////////////////// inline norms +/////////////////////////////////////// + +template inline _Tp cv_abs(_Tp x) { return std::abs(x); } +inline int cv_abs(uchar x) { return x; } +inline int cv_abs(schar x) { return std::abs(x); } +inline int cv_abs(ushort x) { return x; } +inline int cv_abs(short x) { return std::abs(x); } + +template +static inline _AccTp normL2Sqr(const _Tp *a, int n) { + _AccTp s = 0; + int i = 0; +#if CV_ENABLE_UNROLLED + for (; i <= n - 4; i += 4) { + _AccTp v0 = a[i], v1 = a[i + 1], v2 = a[i + 2], v3 = a[i + 3]; + s += v0 * v0 + v1 * v1 + v2 * v2 + v3 * v3; + } +#endif + for (; i < n; i++) { + _AccTp v = a[i]; + s += v * v; + } + return s; +} + +template +static inline _AccTp normL1(const _Tp *a, int n) { + _AccTp s = 0; + int i = 0; +#if CV_ENABLE_UNROLLED + for (; i <= n - 4; i += 4) { + s += (_AccTp)cv_abs(a[i]) + (_AccTp)cv_abs(a[i + 1]) + + (_AccTp)cv_abs(a[i + 2]) + (_AccTp)cv_abs(a[i + 3]); + } +#endif + for (; i < n; i++) + s += cv_abs(a[i]); + return s; +} + +template +static inline _AccTp normInf(const _Tp *a, int n) { + _AccTp s = 0; + for (int i = 0; i < n; i++) + s = std::max(s, (_AccTp)cv_abs(a[i])); + return s; +} + +template +static inline _AccTp normL2Sqr(const _Tp *a, const _Tp *b, int n) { + _AccTp s = 0; + int i = 0; +#if CV_ENABLE_UNROLLED + for (; i <= n - 4; i += 4) { + _AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i + 1] - b[i + 1]), + v2 = _AccTp(a[i + 2] - b[i + 2]), v3 = _AccTp(a[i + 3] - b[i + 3]); + s += v0 * v0 + v1 * v1 + v2 * v2 + v3 * v3; + } +#endif + for (; i < n; i++) { + _AccTp v = _AccTp(a[i] - b[i]); + s += v * v; + } + return s; +} + +static inline float normL2Sqr(const float *a, const float *b, int n) { + float s = 0.f; + for (int i = 0; i < n; i++) { + float v = a[i] - b[i]; + s += v * v; + } + return s; +} + +template +static inline _AccTp normL1(const _Tp *a, const _Tp *b, int n) { + _AccTp s = 0; + int i = 0; +#if CV_ENABLE_UNROLLED + for (; i <= n - 4; i += 4) { + _AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i + 1] - b[i + 1]), + v2 = _AccTp(a[i + 2] - b[i + 2]), v3 = _AccTp(a[i + 3] - b[i + 3]); + s += std::abs(v0) + std::abs(v1) + std::abs(v2) + std::abs(v3); + } +#endif + for (; i < n; i++) { + _AccTp v = _AccTp(a[i] - b[i]); + s += std::abs(v); + } + return s; +} + +inline float normL1(const float *a, const float *b, int n) { + float s = 0.f; + for (int i = 0; i < n; i++) { + s += std::abs(a[i] - b[i]); + } + return s; +} + +inline int normL1(const uchar *a, const uchar *b, int n) { + int s = 0; + for (int i = 0; i < n; i++) { + s += std::abs(a[i] - b[i]); + } + return s; +} + +template +static inline _AccTp normInf(const _Tp *a, const _Tp *b, int n) { + _AccTp s = 0; + for (int i = 0; i < n; i++) { + _AccTp v0 = a[i] - b[i]; + s = std::max(s, std::abs(v0)); + } + return s; +} + +/** @brief Computes the cube root of an argument. + + The function cubeRoot computes \f$\sqrt[3]{\texttt{val}}\f$. Negative arguments + are handled correctly. NaN and Inf are not handled. The accuracy approaches the + maximum possible accuracy for single-precision data. + @param val A function argument. + */ +CV_EXPORTS_W float cubeRoot(float val); + +/** @overload + +cubeRoot with argument of `double` type calls `std::cbrt(double)` +*/ +static inline double cubeRoot(double val) { return std::cbrt(val); } + +/** @brief Calculates the angle of a 2D vector in degrees. + + The function fastAtan2 calculates the full-range angle of an input 2D vector. + The angle is measured in degrees and varies from 0 to 360 degrees. The accuracy + is about 0.3 degrees. + @param x x-coordinate of the vector. + @param y y-coordinate of the vector. + */ +CV_EXPORTS_W float fastAtan2(float y, float x); + +/** proxy for hal::LU */ +CV_EXPORTS int LU(float *A, size_t astep, int m, float *b, size_t bstep, int n); +/** proxy for hal::LU */ +CV_EXPORTS int LU(double *A, size_t astep, int m, double *b, size_t bstep, + int n); +/** proxy for hal::Cholesky */ +CV_EXPORTS bool Cholesky(float *A, size_t astep, int m, float *b, size_t bstep, + int n); +/** proxy for hal::Cholesky */ +CV_EXPORTS bool Cholesky(double *A, size_t astep, int m, double *b, + size_t bstep, int n); + +////////////////// forward declarations for important OpenCV types +///////////////////// + +//! @cond IGNORED + +template class Vec; +template class Matx; + +template class Complex; +template class Point_; +template class Point3_; +template class Size_; +template class Rect_; +template class Scalar_; + +class CV_EXPORTS RotatedRect; +class CV_EXPORTS Range; +class CV_EXPORTS TermCriteria; +class CV_EXPORTS KeyPoint; +class CV_EXPORTS DMatch; +class CV_EXPORTS RNG; + +class CV_EXPORTS Mat; +class CV_EXPORTS MatExpr; + +class CV_EXPORTS SparseMat; +typedef Mat MatND; + +template class Mat_; +template class SparseMat_; + +class CV_EXPORTS MatConstIterator; +class CV_EXPORTS SparseMatIterator; +class CV_EXPORTS SparseMatConstIterator; +template class MatIterator_; +template class MatConstIterator_; +template class SparseMatIterator_; +template class SparseMatConstIterator_; + +namespace ipp { +CV_EXPORTS unsigned long long getIppFeatures(); +CV_EXPORTS void setIppStatus(int status, const char *const funcname = NULL, + const char *const filename = NULL, int line = 0); +CV_EXPORTS int getIppStatus(); +CV_EXPORTS String getIppErrorLocation(); +CV_EXPORTS_W bool useIPP(); +CV_EXPORTS_W void setUseIPP(bool flag); +CV_EXPORTS_W String getIppVersion(); + +// IPP Not-Exact mode. This function may force use of IPP then both IPP and +// OpenCV provide proper results but have internal accuracy differences which +// have too much direct or indirect impact on accuracy tests. +CV_EXPORTS_W bool useIPP_NotExact(); +CV_EXPORTS_W void setUseIPP_NotExact(bool flag); +#ifndef DISABLE_OPENCV_3_COMPATIBILITY +static inline bool useIPP_NE() { return useIPP_NotExact(); } +static inline void setUseIPP_NE(bool flag) { setUseIPP_NotExact(flag); } +#endif + +} // namespace ipp + +//! @endcond + +//! @} core_utils + +} // namespace cv + +#include "opencv2/core/check.hpp" +#include "opencv2/core/neon_utils.hpp" +#include "opencv2/core/vsx_utils.hpp" + +#endif // OPENCV_CORE_BASE_HPP diff --git a/third-party/include/opencv2/core/bindings_utils.hpp b/third-party/include/opencv2/core/bindings_utils.hpp new file mode 100644 index 0000000000..416f3d4747 --- /dev/null +++ b/third-party/include/opencv2/core/bindings_utils.hpp @@ -0,0 +1,279 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_BINDINGS_UTILS_HPP +#define OPENCV_CORE_BINDINGS_UTILS_HPP + +#include +#include +#include + +#include + +namespace cv { +namespace utils { +//! @addtogroup core_utils +//! @{ + +CV_EXPORTS_W String dumpInputArray(InputArray argument); + +CV_EXPORTS_W String dumpInputArrayOfArrays(InputArrayOfArrays argument); + +CV_EXPORTS_W String dumpInputOutputArray(InputOutputArray argument); + +CV_EXPORTS_W String +dumpInputOutputArrayOfArrays(InputOutputArrayOfArrays argument); + +CV_WRAP static inline String dumpBool(bool argument) { + return (argument) ? String("Bool: True") : String("Bool: False"); +} + +CV_WRAP static inline String dumpInt(int argument) { + return cv::format("Int: %d", argument); +} + +CV_WRAP static inline String dumpInt64(int64 argument) { + std::ostringstream oss("Int64: ", std::ios::ate); + oss << argument; + return oss.str(); +} + +CV_WRAP static inline String dumpSizeT(size_t argument) { + std::ostringstream oss("size_t: ", std::ios::ate); + oss << argument; + return oss.str(); +} + +CV_WRAP static inline String dumpFloat(float argument) { + return cv::format("Float: %.2f", argument); +} + +CV_WRAP static inline String dumpDouble(double argument) { + return cv::format("Double: %.2f", argument); +} + +CV_WRAP static inline String dumpCString(const char *argument) { + return cv::format("String: %s", argument); +} + +CV_WRAP static inline String dumpString(const String &argument) { + return cv::format("String: %s", argument.c_str()); +} + +CV_WRAP static inline String dumpRect(const Rect &argument) { + return format("rect: (x=%d, y=%d, w=%d, h=%d)", argument.x, argument.y, + argument.width, argument.height); +} + +CV_WRAP static inline String dumpTermCriteria(const TermCriteria &argument) { + return format("term_criteria: (type=%d, max_count=%d, epsilon=%lf", + argument.type, argument.maxCount, argument.epsilon); +} + +CV_WRAP static inline String dumpRotatedRect(const RotatedRect &argument) { + return format("rotated_rect: (c_x=%f, c_y=%f, w=%f, h=%f, a=%f)", + argument.center.x, argument.center.y, argument.size.width, + argument.size.height, argument.angle); +} + +CV_WRAP static inline String dumpRange(const Range &argument) { + if (argument == Range::all()) { + return "range: all"; + } else { + return format("range: (s=%d, e=%d)", argument.start, argument.end); + } +} + +CV_EXPORTS_W String dumpVectorOfInt(const std::vector &vec); + +CV_EXPORTS_W String dumpVectorOfDouble(const std::vector &vec); + +CV_EXPORTS_W String dumpVectorOfRect(const std::vector &vec); + +//! @cond IGNORED + +CV_WRAP static inline String +testOverloadResolution(int value, const Point &point = Point(42, 24)) { + return format("overload (int=%d, point=(x=%d, y=%d))", value, point.x, + point.y); +} + +CV_WRAP static inline String testOverloadResolution(const Rect &rect) { + return format("overload (rect=(x=%d, y=%d, w=%d, h=%d))", rect.x, rect.y, + rect.width, rect.height); +} + +CV_WRAP static inline RotatedRect testRotatedRect(float x, float y, float w, + float h, float angle) { + return RotatedRect(Point2f(x, y), Size2f(w, h), angle); +} + +CV_WRAP static inline std::vector +testRotatedRectVector(float x, float y, float w, float h, float angle) { + std::vector result; + for (int i = 0; i < 10; i++) + result.push_back( + RotatedRect(Point2f(x + i, y + 2 * i), Size2f(w, h), angle + 10 * i)); + return result; +} + +CV_WRAP static inline int testOverwriteNativeMethod(int argument) { + return argument; +} + +CV_WRAP static inline String +testReservedKeywordConversion(int positional_argument, int lambda = 2, + int from = 3) { + return format("arg=%d, lambda=%d, from=%d", positional_argument, lambda, + from); +} + +CV_WRAP static inline void generateVectorOfRect(size_t len, + CV_OUT std::vector &vec) { + vec.resize(len); + if (len > 0) { + RNG rng(12345); + Mat tmp(static_cast(len), 1, CV_32SC4); + rng.fill(tmp, RNG::UNIFORM, 10, 20); + tmp.copyTo(vec); + } +} + +CV_WRAP static inline void generateVectorOfInt(size_t len, + CV_OUT std::vector &vec) { + vec.resize(len); + if (len > 0) { + RNG rng(554433); + Mat tmp(static_cast(len), 1, CV_32SC1); + rng.fill(tmp, RNG::UNIFORM, -10, 10); + tmp.copyTo(vec); + } +} + +CV_WRAP static inline void generateVectorOfMat(size_t len, int rows, int cols, + int dtype, + CV_OUT std::vector &vec) { + vec.resize(len); + if (len > 0) { + RNG rng(65431); + for (size_t i = 0; i < len; ++i) { + vec[i].create(rows, cols, dtype); + rng.fill(vec[i], RNG::UNIFORM, 0, 10); + } + } +} + +CV_WRAP static inline AsyncArray testAsyncArray(InputArray argument) { + AsyncPromise p; + p.setValue(argument); + return p.getArrayResult(); +} + +CV_WRAP static inline AsyncArray testAsyncException() { + AsyncPromise p; + return p.getArrayResult(); +} + +CV_WRAP static inline String dumpVec2i(const cv::Vec2i value = cv::Vec2i(42, + 24)) { + return format("Vec2i(%d, %d)", value[0], value[1]); +} + +struct CV_EXPORTS_W_SIMPLE ClassWithKeywordProperties { + CV_PROP_RW int lambda; + CV_PROP int except; + + CV_WRAP explicit ClassWithKeywordProperties(int lambda_arg = 24, + int except_arg = 42) { + lambda = lambda_arg; + except = except_arg; + } +}; + +struct CV_EXPORTS_W_PARAMS FunctionParams { + CV_PROP_RW int lambda = -1; + CV_PROP_RW float sigma = 0.0f; + + FunctionParams &setLambda(int value) CV_NOEXCEPT { + lambda = value; + return *this; + } + + FunctionParams &setSigma(float value) CV_NOEXCEPT { + sigma = value; + return *this; + } +}; + +CV_WRAP static inline String +copyMatAndDumpNamedArguments(InputArray src, OutputArray dst, + const FunctionParams ¶ms = FunctionParams()) { + src.copyTo(dst); + return format("lambda=%d, sigma=%.1f", params.lambda, params.sigma); +} + +namespace nested { +CV_WRAP static inline bool testEchoBooleanFunction(bool flag) { return flag; } + +class CV_EXPORTS_W CV_WRAP_AS(ExportClassName) OriginalClassName { +public: + struct CV_EXPORTS_W_SIMPLE Params { + CV_PROP_RW int int_value; + CV_PROP_RW float float_value; + + CV_WRAP explicit Params(int int_param = 123, float float_param = 3.5f) { + int_value = int_param; + float_value = float_param; + } + }; + + explicit OriginalClassName( + const OriginalClassName::Params ¶ms = OriginalClassName::Params()) { + params_ = params; + } + + CV_WRAP int getIntParam() const { return params_.int_value; } + + CV_WRAP float getFloatParam() const { return params_.float_value; } + + CV_WRAP static std::string originalName() { return "OriginalClassName"; } + + CV_WRAP static Ptr create( + const OriginalClassName::Params ¶ms = OriginalClassName::Params()) { + return makePtr(params); + } + +private: + OriginalClassName::Params params_; +}; + +typedef OriginalClassName::Params OriginalClassName_Params; +} // namespace nested + +//! @endcond IGNORED + +namespace fs { +CV_EXPORTS_W cv::String getCacheDirectoryForDownloads(); +} // namespace fs + +//! @} // core_utils +} // namespace utils + +//! @cond IGNORED + +CV_WRAP static inline int setLogLevel(int level) { + // NB: Binding generators doesn't work with enums properly yet, so we define + // separate overload here + return cv::utils::logging::setLogLevel((cv::utils::logging::LogLevel)level); +} + +CV_WRAP static inline int getLogLevel() { + return cv::utils::logging::getLogLevel(); +} + +//! @endcond IGNORED + +} // namespace cv + +#endif // OPENCV_CORE_BINDINGS_UTILS_HPP diff --git a/third-party/include/opencv2/core/bufferpool.hpp b/third-party/include/opencv2/core/bufferpool.hpp new file mode 100644 index 0000000000..8796de938d --- /dev/null +++ b/third-party/include/opencv2/core/bufferpool.hpp @@ -0,0 +1,39 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved. + +#ifndef OPENCV_CORE_BUFFER_POOL_HPP +#define OPENCV_CORE_BUFFER_POOL_HPP + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4265) +#endif + +namespace cv { + +//! @addtogroup core_opencl +//! @{ + +class BufferPoolController { +protected: + ~BufferPoolController() {} + +public: + virtual size_t getReservedSize() const = 0; + virtual size_t getMaxReservedSize() const = 0; + virtual void setMaxReservedSize(size_t size) = 0; + virtual void freeAllReservedBuffers() = 0; +}; + +//! @} + +} // namespace cv + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // OPENCV_CORE_BUFFER_POOL_HPP diff --git a/third-party/include/opencv2/core/check.hpp b/third-party/include/opencv2/core/check.hpp new file mode 100644 index 0000000000..cfcfe0e814 --- /dev/null +++ b/third-party/include/opencv2/core/check.hpp @@ -0,0 +1,231 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_CHECK_HPP +#define OPENCV_CORE_CHECK_HPP + +#include + +namespace cv { + +/** Returns string of cv::Mat depth value: CV_8U -> "CV_8U" or "" + */ +CV_EXPORTS const char *depthToString(int depth); + +/** Returns string of cv::Mat depth value: CV_8UC3 -> "CV_8UC3" or "" */ +CV_EXPORTS String typeToString(int type); + +//! @cond IGNORED +namespace detail { + +/** Returns string of cv::Mat depth value: CV_8U -> "CV_8U" or NULL */ +CV_EXPORTS const char *depthToString_(int depth); + +/** Returns string of cv::Mat depth value: CV_8UC3 -> "CV_8UC3" or cv::String() + */ +CV_EXPORTS cv::String typeToString_(int type); + +enum TestOp { + TEST_CUSTOM = 0, + TEST_EQ = 1, + TEST_NE = 2, + TEST_LE = 3, + TEST_LT = 4, + TEST_GE = 5, + TEST_GT = 6, + CV__LAST_TEST_OP +}; + +struct CheckContext { + const char *func; + const char *file; + int line; + enum TestOp testOp; + const char *message; + const char *p1_str; + const char *p2_str; +}; + +#ifndef CV__CHECK_FILENAME +#define CV__CHECK_FILENAME __FILE__ +#endif + +#ifndef CV__CHECK_FUNCTION +#if defined _MSC_VER +#define CV__CHECK_FUNCTION __FUNCSIG__ +#elif defined __GNUC__ +#define CV__CHECK_FUNCTION __PRETTY_FUNCTION__ +#else +#define CV__CHECK_FUNCTION "" +#endif +#endif + +#define CV__CHECK_LOCATION_VARNAME(id) \ + CVAUX_CONCAT(CVAUX_CONCAT(__cv_check_, id), __LINE__) +#define CV__DEFINE_CHECK_CONTEXT(id, message, testOp, p1_str, p2_str) \ + static const cv::detail::CheckContext CV__CHECK_LOCATION_VARNAME(id) = { \ + CV__CHECK_FUNCTION, CV__CHECK_FILENAME, __LINE__, testOp, \ + "" message, "" p1_str, "" p2_str} + +CV_EXPORTS void CV_NORETURN check_failed_auto(const bool v1, const bool v2, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const int v1, const int v2, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const size_t v1, const size_t v2, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const float v1, const float v2, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const double v1, const double v2, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const Size_ v1, + const Size_ v2, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatDepth(const int v1, const int v2, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatType(const int v1, const int v2, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatChannels(const int v1, const int v2, + const CheckContext &ctx); + +CV_EXPORTS void CV_NORETURN check_failed_true(const bool v, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_false(const bool v, + const CheckContext &ctx); + +CV_EXPORTS void CV_NORETURN check_failed_auto(const int v, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const size_t v, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const float v, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const double v, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const Size_ v, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_auto(const std::string &v1, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatDepth(const int v, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatType(const int v, + const CheckContext &ctx); +CV_EXPORTS void CV_NORETURN check_failed_MatChannels(const int v, + const CheckContext &ctx); + +#define CV__TEST_EQ(v1, v2) ((v1) == (v2)) +#define CV__TEST_NE(v1, v2) ((v1) != (v2)) +#define CV__TEST_LE(v1, v2) ((v1) <= (v2)) +#define CV__TEST_LT(v1, v2) ((v1) < (v2)) +#define CV__TEST_GE(v1, v2) ((v1) >= (v2)) +#define CV__TEST_GT(v1, v2) ((v1) > (v2)) + +#define CV__CHECK(id, op, type, v1, v2, v1_str, v2_str, msg_str) \ + do { \ + if (CV__TEST_##op((v1), (v2))) \ + ; \ + else { \ + CV__DEFINE_CHECK_CONTEXT(id, msg_str, cv::detail::TEST_##op, v1_str, \ + v2_str); \ + cv::detail::check_failed_##type((v1), (v2), \ + CV__CHECK_LOCATION_VARNAME(id)); \ + } \ + } while (0) + +#define CV__CHECK_CUSTOM_TEST(id, type, v, test_expr, v_str, test_expr_str, \ + msg_str) \ + do { \ + if (!!(test_expr)) \ + ; \ + else { \ + CV__DEFINE_CHECK_CONTEXT(id, msg_str, cv::detail::TEST_CUSTOM, v_str, \ + test_expr_str); \ + cv::detail::check_failed_##type((v), CV__CHECK_LOCATION_VARNAME(id)); \ + } \ + } while (0) + +} // namespace detail +//! @endcond + +/// Supported values of these types: int, float, double +#define CV_CheckEQ(v1, v2, msg) CV__CHECK(_, EQ, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckNE(v1, v2, msg) CV__CHECK(_, NE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckLE(v1, v2, msg) CV__CHECK(_, LE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckLT(v1, v2, msg) CV__CHECK(_, LT, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckGE(v1, v2, msg) CV__CHECK(_, GE, auto, v1, v2, #v1, #v2, msg) +#define CV_CheckGT(v1, v2, msg) CV__CHECK(_, GT, auto, v1, v2, #v1, #v2, msg) + +/// Check with additional "decoding" of type values in error message +#define CV_CheckTypeEQ(t1, t2, msg) \ + CV__CHECK(_, EQ, MatType, t1, t2, #t1, #t2, msg) +/// Check with additional "decoding" of depth values in error message +#define CV_CheckDepthEQ(d1, d2, msg) \ + CV__CHECK(_, EQ, MatDepth, d1, d2, #d1, #d2, msg) + +#define CV_CheckChannelsEQ(c1, c2, msg) \ + CV__CHECK(_, EQ, MatChannels, c1, c2, #c1, #c2, msg) + +/// Example: type == CV_8UC1 || type == CV_8UC3 +#define CV_CheckType(t, test_expr, msg) \ + CV__CHECK_CUSTOM_TEST(_, MatType, t, (test_expr), #t, #test_expr, msg) + +/// Example: depth == CV_32F || depth == CV_64F +#define CV_CheckDepth(t, test_expr, msg) \ + CV__CHECK_CUSTOM_TEST(_, MatDepth, t, (test_expr), #t, #test_expr, msg) + +/// Example: channel == 1 || channel == 3 +#define CV_CheckChannels(t, test_expr, msg) \ + CV__CHECK_CUSTOM_TEST(_, MatChannels, t, (test_expr), #t, #test_expr, msg) + +/// Example: v == A || v == B +#define CV_Check(v, test_expr, msg) \ + CV__CHECK_CUSTOM_TEST(_, auto, v, (test_expr), #v, #test_expr, msg) + +/// Example: v == true +#define CV_CheckTrue(v, msg) CV__CHECK_CUSTOM_TEST(_, true, v, v, #v, "", msg) + +/// Example: v == false +#define CV_CheckFalse(v, msg) \ + CV__CHECK_CUSTOM_TEST(_, false, v, (!(v)), #v, "", msg) + +/// Some complex conditions: CV_Check(src2, src2.empty() || (src2.type() == +/// src1.type() && src2.size() == src1.size()), "src2 should have same size/type +/// as src1") +// TODO define pretty-printers + +#ifndef NDEBUG +#define CV_DbgCheck(v, test_expr, msg) \ + CV__CHECK_CUSTOM_TEST(_, auto, v, (test_expr), #v, #test_expr, msg) +#define CV_DbgCheckEQ(v1, v2, msg) CV__CHECK(_, EQ, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckNE(v1, v2, msg) CV__CHECK(_, NE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckLE(v1, v2, msg) CV__CHECK(_, LE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckLT(v1, v2, msg) CV__CHECK(_, LT, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckGE(v1, v2, msg) CV__CHECK(_, GE, auto, v1, v2, #v1, #v2, msg) +#define CV_DbgCheckGT(v1, v2, msg) CV__CHECK(_, GT, auto, v1, v2, #v1, #v2, msg) +#else +#define CV_DbgCheck(v, test_expr, msg) \ + do { \ + } while (0) +#define CV_DbgCheckEQ(v1, v2, msg) \ + do { \ + } while (0) +#define CV_DbgCheckNE(v1, v2, msg) \ + do { \ + } while (0) +#define CV_DbgCheckLE(v1, v2, msg) \ + do { \ + } while (0) +#define CV_DbgCheckLT(v1, v2, msg) \ + do { \ + } while (0) +#define CV_DbgCheckGE(v1, v2, msg) \ + do { \ + } while (0) +#define CV_DbgCheckGT(v1, v2, msg) \ + do { \ + } while (0) +#endif + +} // namespace cv + +#endif // OPENCV_CORE_CHECK_HPP diff --git a/third-party/include/opencv2/core/core.hpp b/third-party/include/opencv2/core/core.hpp new file mode 100644 index 0000000000..a81cf56630 --- /dev/null +++ b/third-party/include/opencv2/core/core.hpp @@ -0,0 +1,55 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this +license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright +notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote +products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" +and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are +disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any +direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/core.hpp" diff --git a/third-party/include/opencv2/core/core_c.h b/third-party/include/opencv2/core/core_c.h new file mode 100644 index 0000000000..657d6bfd54 --- /dev/null +++ b/third-party/include/opencv2/core/core_c.h @@ -0,0 +1,3261 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this +license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright +notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote +products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" +and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are +disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any +direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_C_H +#define OPENCV_CORE_C_H + +#include "opencv2/core/types_c.h" + +#ifdef __cplusplus +/* disable MSVC warning C4190 / clang-cl -Wreturn-type-c-linkage: + 'function' has C-linkage specified, but returns UDT 'typename' + which is incompatible with C + + It is OK to disable it because we only extend few plain structures with + C++ constructors for simpler interoperability with C++ API of the library +*/ +#if defined(__clang__) +// handle clang on Linux and clang-cl (i. e. clang on Windows) first +#pragma GCC diagnostic ignored "-Wreturn-type-c-linkage" +#elif defined(_MSC_VER) +// then handle MSVC +#pragma warning(disable : 4190) +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup core_c + @{ +*/ + +/****************************************************************************************\ +* Array allocation, deallocation, initialization and access to elements +* +\****************************************************************************************/ + +/** `malloc` wrapper. + If there is no enough memory, the function + (as well as other OpenCV functions that call cvAlloc) + raises an error. */ +CVAPI(void *) cvAlloc(size_t size); + +/** `free` wrapper. + Here and further all the memory releasing functions + (that all call cvFree) take double pointer in order to + to clear pointer to the data after releasing it. + Passing pointer to NULL pointer is Ok: nothing happens in this case +*/ +CVAPI(void) cvFree_(void *ptr); +#define cvFree(ptr) (cvFree_(*(ptr)), *(ptr) = 0) + +/** @brief Creates an image header but does not allocate the image data. + +@param size Image width and height +@param depth Image depth (see cvCreateImage ) +@param channels Number of channels (see cvCreateImage ) + */ +CVAPI(IplImage *) cvCreateImageHeader(CvSize size, int depth, int channels); + +/** @brief Initializes an image header that was previously allocated. + +The returned IplImage\* points to the initialized header. +@param image Image header to initialize +@param size Image width and height +@param depth Image depth (see cvCreateImage ) +@param channels Number of channels (see cvCreateImage ) +@param origin Top-left IPL_ORIGIN_TL or bottom-left IPL_ORIGIN_BL +@param align Alignment for image rows, typically 4 or 8 bytes + */ +CVAPI(IplImage *) +cvInitImageHeader(IplImage *image, CvSize size, int depth, int channels, + int origin CV_DEFAULT(0), int align CV_DEFAULT(4)); + +/** @brief Creates an image header and allocates the image data. + +This function call is equivalent to the following code: +@code + header = cvCreateImageHeader(size, depth, channels); + cvCreateData(header); +@endcode +@param size Image width and height +@param depth Bit depth of image elements. See IplImage for valid depths. +@param channels Number of channels per pixel. See IplImage for details. This +function only creates images with interleaved channels. + */ +CVAPI(IplImage *) cvCreateImage(CvSize size, int depth, int channels); + +/** @brief Deallocates an image header. + +This call is an analogue of : +@code + if(image ) + { + iplDeallocate(*image, IPL_IMAGE_HEADER | IPL_IMAGE_ROI); + *image = 0; + } +@endcode +but it does not use IPL functions by default (see the +CV_TURN_ON_IPL_COMPATIBILITY macro). +@param image Double pointer to the image header + */ +CVAPI(void) cvReleaseImageHeader(IplImage **image); + +/** @brief Deallocates the image header and the image data. + +This call is a shortened form of : +@code + if(*image ) + { + cvReleaseData(*image); + cvReleaseImageHeader(image); + } +@endcode +@param image Double pointer to the image header +*/ +CVAPI(void) cvReleaseImage(IplImage **image); + +/** Creates a copy of IPL image (widthStep may differ) */ +CVAPI(IplImage *) cvCloneImage(const IplImage *image); + +/** @brief Sets the channel of interest in an IplImage. + +If the ROI is set to NULL and the coi is *not* 0, the ROI is allocated. Most +OpenCV functions do *not* support the COI setting, so to process an individual +image/matrix channel one may copy (via cvCopy or cvSplit) the channel to a +separate image/matrix, process it and then copy the result back (via cvCopy or +cvMerge) if needed. +@param image A pointer to the image header +@param coi The channel of interest. 0 - all channels are selected, 1 - first +channel is selected, etc. Note that the channel indices become 1-based. + */ +CVAPI(void) cvSetImageCOI(IplImage *image, int coi); + +/** @brief Returns the index of the channel of interest. + +Returns the channel of interest of in an IplImage. Returned values correspond to +the coi in cvSetImageCOI. +@param image A pointer to the image header + */ +CVAPI(int) cvGetImageCOI(const IplImage *image); + +/** @brief Sets an image Region Of Interest (ROI) for a given rectangle. + +If the original image ROI was NULL and the rect is not the whole image, the ROI +structure is allocated. + +Most OpenCV functions support the use of ROI and treat the image rectangle as a +separate image. For example, all of the pixel coordinates are counted from the +top-left (or bottom-left) corner of the ROI, not the original image. +@param image A pointer to the image header +@param rect The ROI rectangle + */ +CVAPI(void) cvSetImageROI(IplImage *image, CvRect rect); + +/** @brief Resets the image ROI to include the entire image and releases the ROI +structure. + +This produces a similar result to the following, but in addition it releases the +ROI structure. : +@code + cvSetImageROI(image, cvRect(0, 0, image->width, image->height )); + cvSetImageCOI(image, 0); +@endcode +@param image A pointer to the image header + */ +CVAPI(void) cvResetImageROI(IplImage *image); + +/** @brief Returns the image ROI. + +If there is no ROI set, cvRect(0,0,image-\>width,image-\>height) is returned. +@param image A pointer to the image header + */ +CVAPI(CvRect) cvGetImageROI(const IplImage *image); + +/** @brief Creates a matrix header but does not allocate the matrix data. + +The function allocates a new matrix header and returns a pointer to it. The +matrix data can then be allocated using cvCreateData or set explicitly to +user-allocated data via cvSetData. +@param rows Number of rows in the matrix +@param cols Number of columns in the matrix +@param type Type of the matrix elements, see cvCreateMat + */ +CVAPI(CvMat *) cvCreateMatHeader(int rows, int cols, int type); + +#define CV_AUTOSTEP 0x7fffffff + +/** @brief Initializes a pre-allocated matrix header. + +This function is often used to process raw data with OpenCV matrix functions. +For example, the following code computes the matrix product of two matrices, +stored as ordinary arrays: +@code + double a[] = { 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12 }; + + double b[] = { 1, 5, 9, + 2, 6, 10, + 3, 7, 11, + 4, 8, 12 }; + + double c[9]; + CvMat Ma, Mb, Mc ; + + cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a); + cvInitMatHeader(&Mb, 4, 3, CV_64FC1, b); + cvInitMatHeader(&Mc, 3, 3, CV_64FC1, c); + + cvMatMulAdd(&Ma, &Mb, 0, &Mc); + // the c array now contains the product of a (3x4) and b (4x3) +@endcode +@param mat A pointer to the matrix header to be initialized +@param rows Number of rows in the matrix +@param cols Number of columns in the matrix +@param type Type of the matrix elements, see cvCreateMat . +@param data Optional: data pointer assigned to the matrix header +@param step Optional: full row width in bytes of the assigned data. By default, +the minimal possible step is used which assumes there are no gaps between +subsequent rows of the matrix. + */ +CVAPI(CvMat *) +cvInitMatHeader(CvMat *mat, int rows, int cols, int type, + void *data CV_DEFAULT(NULL), int step CV_DEFAULT(CV_AUTOSTEP)); + +/** @brief Creates a matrix header and allocates the matrix data. + +The function call is equivalent to the following code: +@code + CvMat* mat = cvCreateMatHeader(rows, cols, type); + cvCreateData(mat); +@endcode +@param rows Number of rows in the matrix +@param cols Number of columns in the matrix +@param type The type of the matrix elements in the form +CV_\\C\ , where S=signed, U=unsigned, +F=float. For example, CV _ 8UC1 means the elements are 8-bit unsigned and the +there is 1 channel, and CV _ 32SC2 means the elements are 32-bit signed and +there are 2 channels. + */ +CVAPI(CvMat *) cvCreateMat(int rows, int cols, int type); + +/** @brief Deallocates a matrix. + +The function decrements the matrix data reference counter and deallocates matrix +header. If the data reference counter is 0, it also deallocates the data. : +@code + if(*mat ) + cvDecRefData(*mat); + cvFree((void**)mat); +@endcode +@param mat Double pointer to the matrix + */ +CVAPI(void) cvReleaseMat(CvMat **mat); + +/** @brief Decrements an array data reference counter. + +The function decrements the data reference counter in a CvMat or CvMatND if the +reference counter + +pointer is not NULL. If the counter reaches zero, the data is deallocated. In +the current implementation the reference counter is not NULL only if the data +was allocated using the cvCreateData function. The counter will be NULL in other +cases such as: external data was assigned to the header using cvSetData, header +is part of a larger matrix or image, or the header was converted from an image +or n-dimensional matrix header. +@param arr Pointer to an array header + */ +CV_INLINE void cvDecRefData(CvArr *arr) { + if (CV_IS_MAT(arr)) { + CvMat *mat = (CvMat *)arr; + mat->data.ptr = NULL; + if (mat->refcount != NULL && --*mat->refcount == 0) + cvFree(&mat->refcount); + mat->refcount = NULL; + } else if (CV_IS_MATND(arr)) { + CvMatND *mat = (CvMatND *)arr; + mat->data.ptr = NULL; + if (mat->refcount != NULL && --*mat->refcount == 0) + cvFree(&mat->refcount); + mat->refcount = NULL; + } +} + +/** @brief Increments array data reference counter. + +The function increments CvMat or CvMatND data reference counter and returns the +new counter value if the reference counter pointer is not NULL, otherwise it +returns zero. +@param arr Array header + */ +CV_INLINE int cvIncRefData(CvArr *arr) { + int refcount = 0; + if (CV_IS_MAT(arr)) { + CvMat *mat = (CvMat *)arr; + if (mat->refcount != NULL) + refcount = ++*mat->refcount; + } else if (CV_IS_MATND(arr)) { + CvMatND *mat = (CvMatND *)arr; + if (mat->refcount != NULL) + refcount = ++*mat->refcount; + } + return refcount; +} + +/** Creates an exact copy of the input matrix (except, may be, step value) */ +CVAPI(CvMat *) cvCloneMat(const CvMat *mat); + +/** @brief Returns matrix header corresponding to the rectangular sub-array of +input image or matrix. + +The function returns header, corresponding to a specified rectangle of the input +array. In other + +words, it allows the user to treat a rectangular part of input array as a +stand-alone array. ROI is taken into account by the function so the sub-array of +ROI is actually extracted. +@param arr Input array +@param submat Pointer to the resultant sub-array header +@param rect Zero-based coordinates of the rectangle of interest + */ +CVAPI(CvMat *) cvGetSubRect(const CvArr *arr, CvMat *submat, CvRect rect); +#define cvGetSubArr cvGetSubRect + +/** @brief Returns array row or row span. + +The function returns the header, corresponding to a specified row/row span of +the input array. cvGetRow(arr, submat, row) is a shortcut for cvGetRows(arr, +submat, row, row+1). +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param start_row Zero-based index of the starting row (inclusive) of the span +@param end_row Zero-based index of the ending row (exclusive) of the span +@param delta_row Index step in the row span. That is, the function extracts +every delta_row -th row from start_row and up to (but not including) end_row . + */ +CVAPI(CvMat *) +cvGetRows(const CvArr *arr, CvMat *submat, int start_row, int end_row, + int delta_row CV_DEFAULT(1)); + +/** @overload +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param row Zero-based index of the selected row +*/ +CV_INLINE CvMat *cvGetRow(const CvArr *arr, CvMat *submat, int row) { + return cvGetRows(arr, submat, row, row + 1, 1); +} + +/** @brief Returns one of more array columns. + +The function returns the header, corresponding to a specified column span of the +input array. That + +is, no data is copied. Therefore, any modifications of the submatrix will affect +the original array. If you need to copy the columns, use cvCloneMat. +cvGetCol(arr, submat, col) is a shortcut for cvGetCols(arr, submat, col, col+1). +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param start_col Zero-based index of the starting column (inclusive) of the span +@param end_col Zero-based index of the ending column (exclusive) of the span + */ +CVAPI(CvMat *) +cvGetCols(const CvArr *arr, CvMat *submat, int start_col, int end_col); + +/** @overload +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param col Zero-based index of the selected column +*/ +CV_INLINE CvMat *cvGetCol(const CvArr *arr, CvMat *submat, int col) { + return cvGetCols(arr, submat, col, col + 1); +} + +/** @brief Returns one of array diagonals. + +The function returns the header, corresponding to a specified diagonal of the +input array. +@param arr Input array +@param submat Pointer to the resulting sub-array header +@param diag Index of the array diagonal. Zero value corresponds to the main +diagonal, -1 corresponds to the diagonal above the main, 1 corresponds to the +diagonal below the main, and so forth. + */ +CVAPI(CvMat *) +cvGetDiag(const CvArr *arr, CvMat *submat, int diag CV_DEFAULT(0)); + +/** low-level scalar <-> raw data conversion functions */ +CVAPI(void) +cvScalarToRawData(const CvScalar *scalar, void *data, int type, + int extend_to_12 CV_DEFAULT(0)); + +CVAPI(void) cvRawDataToScalar(const void *data, int type, CvScalar *scalar); + +/** @brief Creates a new matrix header but does not allocate the matrix data. + +The function allocates a header for a multi-dimensional dense array. The array +data can further be allocated using cvCreateData or set explicitly to +user-allocated data via cvSetData. +@param dims Number of array dimensions +@param sizes Array of dimension sizes +@param type Type of array elements, see cvCreateMat + */ +CVAPI(CvMatND *) cvCreateMatNDHeader(int dims, const int *sizes, int type); + +/** @brief Creates the header and allocates the data for a multi-dimensional +dense array. + +This function call is equivalent to the following code: +@code + CvMatND* mat = cvCreateMatNDHeader(dims, sizes, type); + cvCreateData(mat); +@endcode +@param dims Number of array dimensions. This must not exceed CV_MAX_DIM (32 by +default, but can be changed at build time). +@param sizes Array of dimension sizes. +@param type Type of array elements, see cvCreateMat . + */ +CVAPI(CvMatND *) cvCreateMatND(int dims, const int *sizes, int type); + +/** @brief Initializes a pre-allocated multi-dimensional array header. + +@param mat A pointer to the array header to be initialized +@param dims The number of array dimensions +@param sizes An array of dimension sizes +@param type Type of array elements, see cvCreateMat +@param data Optional data pointer assigned to the matrix header + */ +CVAPI(CvMatND *) +cvInitMatNDHeader(CvMatND *mat, int dims, const int *sizes, int type, + void *data CV_DEFAULT(NULL)); + +/** @brief Deallocates a multi-dimensional array. + +The function decrements the array data reference counter and releases the array +header. If the reference counter reaches 0, it also deallocates the data. : +@code + if(*mat ) + cvDecRefData(*mat); + cvFree((void**)mat); +@endcode +@param mat Double pointer to the array + */ +CV_INLINE void cvReleaseMatND(CvMatND **mat) { cvReleaseMat((CvMat **)mat); } + +/** Creates a copy of CvMatND (except, may be, steps) */ +CVAPI(CvMatND *) cvCloneMatND(const CvMatND *mat); + +/** @brief Creates sparse array. + +The function allocates a multi-dimensional sparse array. Initially the array +contain no elements, that is PtrND and other related functions will return 0 for +every index. +@param dims Number of array dimensions. In contrast to the dense matrix, the +number of dimensions is practically unlimited (up to \f$2^{16}\f$ ). +@param sizes Array of dimension sizes +@param type Type of array elements. The same as for CvMat + */ +CVAPI(CvSparseMat *) cvCreateSparseMat(int dims, const int *sizes, int type); + +/** @brief Deallocates sparse array. + +The function releases the sparse array and clears the array pointer upon exit. +@param mat Double pointer to the array + */ +CVAPI(void) cvReleaseSparseMat(CvSparseMat **mat); + +/** Creates a copy of CvSparseMat (except, may be, zero items) */ +CVAPI(CvSparseMat *) cvCloneSparseMat(const CvSparseMat *mat); + +/** @brief Initializes sparse array elements iterator. + +The function initializes iterator of sparse array elements and returns pointer +to the first element, or NULL if the array is empty. +@param mat Input array +@param mat_iterator Initialized iterator + */ +CVAPI(CvSparseNode *) +cvInitSparseMatIterator(const CvSparseMat *mat, + CvSparseMatIterator *mat_iterator); + +/** @brief Returns the next sparse matrix element + +The function moves iterator to the next sparse matrix element and returns +pointer to it. In the current version there is no any particular order of the +elements, because they are stored in the hash table. The sample below +demonstrates how to iterate through the sparse matrix: +@code + // print all the non-zero sparse matrix elements and compute their sum + double sum = 0; + int i, dims = cvGetDims(sparsemat); + CvSparseMatIterator it; + CvSparseNode* node = cvInitSparseMatIterator(sparsemat, &it); + + for(; node != 0; node = cvGetNextSparseNode(&it)) + { + int* idx = CV_NODE_IDX(array, node); + float val = *(float*)CV_NODE_VAL(array, node); + printf("M"); + for(i = 0; i < dims; i++ ) + printf("[%d]", idx[i]); + printf("=%g\n", val); + + sum += val; + } + + printf("nTotal sum = %g\n", sum); +@endcode +@param mat_iterator Sparse array iterator + */ +CV_INLINE CvSparseNode *cvGetNextSparseNode(CvSparseMatIterator *mat_iterator) { + if (mat_iterator->node->next) + return mat_iterator->node = mat_iterator->node->next; + else { + int idx; + for (idx = ++mat_iterator->curidx; idx < mat_iterator->mat->hashsize; + idx++) { + CvSparseNode *node = (CvSparseNode *)mat_iterator->mat->hashtable[idx]; + if (node) { + mat_iterator->curidx = idx; + return mat_iterator->node = node; + } + } + return NULL; + } +} + +#define CV_MAX_ARR 10 + +/** matrix iterator: used for n-ary operations on dense arrays */ +typedef struct CvNArrayIterator { + int count; /**< number of arrays */ + int dims; /**< number of dimensions to iterate */ + CvSize size; /**< maximal common linear size: { width = size, height = 1 } */ + uchar *ptr[CV_MAX_ARR]; /**< pointers to the array slices */ + int stack[CV_MAX_DIM]; /**< for internal use */ + CvMatND *hdr[CV_MAX_ARR]; /**< pointers to the headers of the + matrices that are processed */ +} CvNArrayIterator; + +#define CV_NO_DEPTH_CHECK 1 +#define CV_NO_CN_CHECK 2 +#define CV_NO_SIZE_CHECK 4 + +/** initializes iterator that traverses through several arrays simultaneously + (the function together with cvNextArraySlice is used for + N-ari element-wise operations) */ +CVAPI(int) +cvInitNArrayIterator(int count, CvArr **arrs, const CvArr *mask, CvMatND *stubs, + CvNArrayIterator *array_iterator, int flags CV_DEFAULT(0)); + +/** returns zero value if iteration is finished, non-zero (slice length) + * otherwise */ +CVAPI(int) cvNextNArraySlice(CvNArrayIterator *array_iterator); + +/** @brief Returns type of array elements. + +The function returns type of the array elements. In the case of IplImage the +type is converted to CvMat-like representation. For example, if the image has +been created as: +@code + IplImage* img = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3); +@endcode +The code cvGetElemType(img) will return CV_8UC3. +@param arr Input array + */ +CVAPI(int) cvGetElemType(const CvArr *arr); + +/** @brief Return number of array dimensions + +The function returns the array dimensionality and the array of dimension sizes. +In the case of IplImage or CvMat it always returns 2 regardless of number of +image/matrix rows. For example, the following code calculates total number of +array elements: +@code + int sizes[CV_MAX_DIM]; + int i, total = 1; + int dims = cvGetDims(arr, size); + for(i = 0; i < dims; i++ ) + total *= sizes[i]; +@endcode +@param arr Input array +@param sizes Optional output vector of the array dimension sizes. For 2d arrays +the number of rows (height) goes first, number of columns (width) next. + */ +CVAPI(int) cvGetDims(const CvArr *arr, int *sizes CV_DEFAULT(NULL)); + +/** @brief Returns array size along the specified dimension. + +@param arr Input array +@param index Zero-based dimension index (for matrices 0 means number of rows, 1 +means number of columns; for images 0 means height, 1 means width) + */ +CVAPI(int) cvGetDimSize(const CvArr *arr, int index); + +/** @brief Return pointer to a particular array element. + +The functions return a pointer to a specific array element. Number of array +dimension should match to the number of indices passed to the function except +for cvPtr1D function that can be used for sequential access to 1D, 2D or nD +dense arrays. + +The functions can be used for sparse arrays as well - if the requested node does +not exist they create it and set it to zero. + +All these as well as other functions accessing array elements ( cvGetND , +cvGetRealND , cvSet , cvSetND , cvSetRealND ) raise an error in case if the +element index is out of range. +@param arr Input array +@param idx0 The first zero-based component of the element index +@param type Optional output parameter: type of matrix elements + */ +CVAPI(uchar *) cvPtr1D(const CvArr *arr, int idx0, int *type CV_DEFAULT(NULL)); +/** @overload */ +CVAPI(uchar *) +cvPtr2D(const CvArr *arr, int idx0, int idx1, int *type CV_DEFAULT(NULL)); +/** @overload */ +CVAPI(uchar *) +cvPtr3D(const CvArr *arr, int idx0, int idx1, int idx2, + int *type CV_DEFAULT(NULL)); +/** @overload +@param arr Input array +@param idx Array of the element indices +@param type Optional output parameter: type of matrix elements +@param create_node Optional input parameter for sparse matrices. Non-zero value +of the parameter means that the requested element is created if it does not +exist already. +@param precalc_hashval Optional input parameter for sparse matrices. If the +pointer is not NULL, the function does not recalculate the node hash value, but +takes it from the specified location. It is useful for speeding up pair-wise +operations (TODO: provide an example) +*/ +CVAPI(uchar *) +cvPtrND(const CvArr *arr, const int *idx, int *type CV_DEFAULT(NULL), + int create_node CV_DEFAULT(1), + unsigned *precalc_hashval CV_DEFAULT(NULL)); + +/** @brief Return a specific array element. + +The functions return a specific array element. In the case of a sparse array the +functions return 0 if the requested node does not exist (no new node is created +by the functions). +@param arr Input array +@param idx0 The first zero-based component of the element index + */ +CVAPI(CvScalar) cvGet1D(const CvArr *arr, int idx0); +/** @overload */ +CVAPI(CvScalar) cvGet2D(const CvArr *arr, int idx0, int idx1); +/** @overload */ +CVAPI(CvScalar) cvGet3D(const CvArr *arr, int idx0, int idx1, int idx2); +/** @overload +@param arr Input array +@param idx Array of the element indices +*/ +CVAPI(CvScalar) cvGetND(const CvArr *arr, const int *idx); + +/** @brief Return a specific element of single-channel 1D, 2D, 3D or nD array. + +Returns a specific element of a single-channel array. If the array has multiple +channels, a runtime error is raised. Note that Get?D functions can be used +safely for both single-channel and multiple-channel arrays though they are a bit +slower. + +In the case of a sparse array the functions return 0 if the requested node does +not exist (no new node is created by the functions). +@param arr Input array. Must have a single channel. +@param idx0 The first zero-based component of the element index + */ +CVAPI(double) cvGetReal1D(const CvArr *arr, int idx0); +/** @overload */ +CVAPI(double) cvGetReal2D(const CvArr *arr, int idx0, int idx1); +/** @overload */ +CVAPI(double) cvGetReal3D(const CvArr *arr, int idx0, int idx1, int idx2); +/** @overload +@param arr Input array. Must have a single channel. +@param idx Array of the element indices +*/ +CVAPI(double) cvGetRealND(const CvArr *arr, const int *idx); + +/** @brief Change the particular array element. + +The functions assign the new value to a particular array element. In the case of +a sparse array the functions create the node if it does not exist yet. +@param arr Input array +@param idx0 The first zero-based component of the element index +@param value The assigned value + */ +CVAPI(void) cvSet1D(CvArr *arr, int idx0, CvScalar value); +/** @overload */ +CVAPI(void) cvSet2D(CvArr *arr, int idx0, int idx1, CvScalar value); +/** @overload */ +CVAPI(void) cvSet3D(CvArr *arr, int idx0, int idx1, int idx2, CvScalar value); +/** @overload +@param arr Input array +@param idx Array of the element indices +@param value The assigned value +*/ +CVAPI(void) cvSetND(CvArr *arr, const int *idx, CvScalar value); + +/** @brief Change a specific array element. + +The functions assign a new value to a specific element of a single-channel +array. If the array has multiple channels, a runtime error is raised. Note that +the Set\*D function can be used safely for both single-channel and +multiple-channel arrays, though they are a bit slower. + +In the case of a sparse array the functions create the node if it does not yet +exist. +@param arr Input array +@param idx0 The first zero-based component of the element index +@param value The assigned value + */ +CVAPI(void) cvSetReal1D(CvArr *arr, int idx0, double value); +/** @overload */ +CVAPI(void) cvSetReal2D(CvArr *arr, int idx0, int idx1, double value); +/** @overload */ +CVAPI(void) cvSetReal3D(CvArr *arr, int idx0, int idx1, int idx2, double value); +/** @overload +@param arr Input array +@param idx Array of the element indices +@param value The assigned value +*/ +CVAPI(void) cvSetRealND(CvArr *arr, const int *idx, double value); + +/** clears element of ND dense array, + in case of sparse arrays it deletes the specified node */ +CVAPI(void) cvClearND(CvArr *arr, const int *idx); + +/** @brief Returns matrix header for arbitrary array. + +The function returns a matrix header for the input array that can be a matrix - +CvMat, an image - IplImage, or a multi-dimensional dense array - CvMatND (the +third option is allowed only if allowND != 0) . In the case of matrix the +function simply returns the input pointer. In the case of IplImage\* or CvMatND +it initializes the header structure with parameters of the current image ROI and +returns &header. Because COI is not supported by CvMat, it is returned +separately. + +The function provides an easy way to handle both types of arrays - IplImage and +CvMat using the same code. Input array must have non-zero data pointer, +otherwise the function will report an error. + +@note If the input array is IplImage with planar data layout and COI set, the +function returns the pointer to the selected plane and COI == 0. This feature +allows user to process IplImage structures with planar data layout, even though +OpenCV does not support such images. +@param arr Input array +@param header Pointer to CvMat structure used as a temporary buffer +@param coi Optional output parameter for storing COI +@param allowND If non-zero, the function accepts multi-dimensional dense arrays +(CvMatND\*) and returns 2D matrix (if CvMatND has two dimensions) or 1D matrix +(when CvMatND has 1 dimension or more than 2 dimensions). The CvMatND array must +be continuous. +@sa cvGetImage, cvarrToMat. + */ +CVAPI(CvMat *) +cvGetMat(const CvArr *arr, CvMat *header, int *coi CV_DEFAULT(NULL), + int allowND CV_DEFAULT(0)); + +/** @brief Returns image header for arbitrary array. + +The function returns the image header for the input array that can be a matrix +(CvMat) or image (IplImage). In the case of an image the function simply returns +the input pointer. In the case of CvMat it initializes an image_header structure +with the parameters of the input matrix. Note that if we transform IplImage to +CvMat using cvGetMat and then transform CvMat back to IplImage using this +function, we will get different headers if the ROI is set in the original image. +@param arr Input array +@param image_header Pointer to IplImage structure used as a temporary buffer + */ +CVAPI(IplImage *) cvGetImage(const CvArr *arr, IplImage *image_header); + +/** @brief Changes the shape of a multi-dimensional array without copying the +data. + +The function is an advanced version of cvReshape that can work with +multi-dimensional arrays as well (though it can work with ordinary images and +matrices) and change the number of dimensions. + +Below are the two samples from the cvReshape description rewritten using +cvReshapeMatND: +@code + IplImage* color_img = cvCreateImage(cvSize(320,240), IPL_DEPTH_8U, 3); + IplImage gray_img_hdr, *gray_img; + gray_img = (IplImage*)cvReshapeMatND(color_img, sizeof(gray_img_hdr), +&gray_img_hdr, 1, 0, 0); + ... + int size[] = { 2, 2, 2 }; + CvMatND* mat = cvCreateMatND(3, size, CV_32F); + CvMat row_header, *row; + row = (CvMat*)cvReshapeMatND(mat, sizeof(row_header), &row_header, 0, 1, 0); +@endcode +In C, the header file for this function includes a convenient macro cvReshapeND +that does away with the sizeof_header parameter. So, the lines containing the +call to cvReshapeMatND in the examples may be replaced as follow: +@code + gray_img = (IplImage*)cvReshapeND(color_img, &gray_img_hdr, 1, 0, 0); + ... + row = (CvMat*)cvReshapeND(mat, &row_header, 0, 1, 0); +@endcode +@param arr Input array +@param sizeof_header Size of output header to distinguish between IplImage, +CvMat and CvMatND output headers +@param header Output header to be filled +@param new_cn New number of channels. new_cn = 0 means that the number of +channels remains unchanged. +@param new_dims New number of dimensions. new_dims = 0 means that the number of +dimensions remains the same. +@param new_sizes Array of new dimension sizes. Only new_dims-1 values are used, +because the total number of elements must remain the same. Thus, if new_dims = +1, new_sizes array is not used. + */ +CVAPI(CvArr *) +cvReshapeMatND(const CvArr *arr, int sizeof_header, CvArr *header, int new_cn, + int new_dims, int *new_sizes); + +#define cvReshapeND(arr, header, new_cn, new_dims, new_sizes) \ + cvReshapeMatND((arr), sizeof(*(header)), (header), (new_cn), (new_dims), \ + (new_sizes)) + +/** @brief Changes shape of matrix/image without copying data. + +The function initializes the CvMat header so that it points to the same data as +the original array but has a different shape - different number of channels, +different number of rows, or both. + +The following example code creates one image buffer and two image headers, the +first is for a 320x240x3 image and the second is for a 960x240x1 image: +@code + IplImage* color_img = cvCreateImage(cvSize(320,240), IPL_DEPTH_8U, 3); + CvMat gray_mat_hdr; + IplImage gray_img_hdr, *gray_img; + cvReshape(color_img, &gray_mat_hdr, 1); + gray_img = cvGetImage(&gray_mat_hdr, &gray_img_hdr); +@endcode +And the next example converts a 3x3 matrix to a single 1x9 vector: +@code + CvMat* mat = cvCreateMat(3, 3, CV_32F); + CvMat row_header, *row; + row = cvReshape(mat, &row_header, 0, 1); +@endcode +@param arr Input array +@param header Output header to be filled +@param new_cn New number of channels. 'new_cn = 0' means that the number of +channels remains unchanged. +@param new_rows New number of rows. 'new_rows = 0' means that the number of rows +remains unchanged unless it needs to be changed according to new_cn value. +*/ +CVAPI(CvMat *) +cvReshape(const CvArr *arr, CvMat *header, int new_cn, + int new_rows CV_DEFAULT(0)); + +/** Repeats source 2d array several times in both horizontal and + vertical direction to fill destination array */ +CVAPI(void) cvRepeat(const CvArr *src, CvArr *dst); + +/** @brief Allocates array data + +The function allocates image, matrix or multi-dimensional dense array data. Note +that in the case of matrix types OpenCV allocation functions are used. In the +case of IplImage they are used unless CV_TURN_ON_IPL_COMPATIBILITY() has been +called before. In the latter case IPL functions are used to allocate the data. +@param arr Array header + */ +CVAPI(void) cvCreateData(CvArr *arr); + +/** @brief Releases array data. + +The function releases the array data. In the case of CvMat or CvMatND it simply +calls cvDecRefData(), that is the function can not deallocate external data. See +also the note to cvCreateData . +@param arr Array header + */ +CVAPI(void) cvReleaseData(CvArr *arr); + +/** @brief Assigns user data to the array header. + +The function assigns user data to the array header. Header should be initialized +before using cvCreateMatHeader, cvCreateImageHeader, cvCreateMatNDHeader, +cvInitMatHeader, cvInitImageHeader or cvInitMatNDHeader. +@param arr Array header +@param data User data +@param step Full row length in bytes + */ +CVAPI(void) cvSetData(CvArr *arr, void *data, int step); + +/** @brief Retrieves low-level information about the array. + +The function fills output variables with low-level information about the array +data. All output + +parameters are optional, so some of the pointers may be set to NULL. If the +array is IplImage with ROI set, the parameters of ROI are returned. + +The following example shows how to get access to array elements. It computes +absolute values of the array elements : +@code + float* data; + int step; + CvSize size; + + cvGetRawData(array, (uchar**)&data, &step, &size); + step /= sizeof(data[0]); + + for(int y = 0; y < size.height; y++, data += step ) + for(int x = 0; x < size.width; x++ ) + data[x] = (float)fabs(data[x]); +@endcode +@param arr Array header +@param data Output pointer to the whole image origin or ROI origin if ROI is set +@param step Output full row length in bytes +@param roi_size Output ROI size + */ +CVAPI(void) +cvGetRawData(const CvArr *arr, uchar **data, int *step CV_DEFAULT(NULL), + CvSize *roi_size CV_DEFAULT(NULL)); + +/** @brief Returns size of matrix or image ROI. + +The function returns number of rows (CvSize::height) and number of columns +(CvSize::width) of the input matrix or image. In the case of image the size of +ROI is returned. +@param arr array header + */ +CVAPI(CvSize) cvGetSize(const CvArr *arr); + +/** @brief Copies one array to another. + +The function copies selected elements from an input array to an output array: + +\f[\texttt{dst} (I)= \texttt{src} (I) \quad \text{if} \quad \texttt{mask} (I) +\ne 0.\f] + +If any of the passed arrays is of IplImage type, then its ROI and COI fields are +used. Both arrays must have the same type, the same number of dimensions, and +the same size. The function can also copy sparse arrays (mask is not supported +in this case). +@param src The source array +@param dst The destination array +@param mask Operation mask, 8-bit single channel array; specifies elements of +the destination array to be changed + */ +CVAPI(void) +cvCopy(const CvArr *src, CvArr *dst, const CvArr *mask CV_DEFAULT(NULL)); + +/** @brief Sets every element of an array to a given value. + +The function copies the scalar value to every selected element of the +destination array: +\f[\texttt{arr} (I)= \texttt{value} \quad \text{if} \quad \texttt{mask} (I) \ne +0\f] If array arr is of IplImage type, then is ROI used, but COI must not be +set. +@param arr The destination array +@param value Fill value +@param mask Operation mask, 8-bit single channel array; specifies elements of +the destination array to be changed + */ +CVAPI(void) +cvSet(CvArr *arr, CvScalar value, const CvArr *mask CV_DEFAULT(NULL)); + +/** @brief Clears the array. + +The function clears the array. In the case of dense arrays (CvMat, CvMatND or +IplImage), cvZero(array) is equivalent to cvSet(array,cvScalarAll(0),0). In the +case of sparse arrays all the elements are removed. +@param arr Array to be cleared + */ +CVAPI(void) cvSetZero(CvArr *arr); +#define cvZero cvSetZero + +/** Splits a multi-channel array into the set of single-channel arrays or + extracts particular [color] plane */ +CVAPI(void) +cvSplit(const CvArr *src, CvArr *dst0, CvArr *dst1, CvArr *dst2, CvArr *dst3); + +/** Merges a set of single-channel arrays into the single multi-channel array + or inserts one particular [color] plane to the array */ +CVAPI(void) +cvMerge(const CvArr *src0, const CvArr *src1, const CvArr *src2, + const CvArr *src3, CvArr *dst); + +/** Copies several channels from input arrays to + certain channels of output arrays */ +CVAPI(void) +cvMixChannels(const CvArr **src, int src_count, CvArr **dst, int dst_count, + const int *from_to, int pair_count); + +/** @brief Converts one array to another with optional linear transformation. + +The function has several different purposes, and thus has several different +names. It copies one array to another with optional scaling, which is performed +first, and/or optional type conversion, performed after: + +\f[\texttt{dst} (I) = \texttt{scale} \texttt{src} (I) + ( \texttt{shift} _0, +\texttt{shift} _1,...)\f] + +All the channels of multi-channel arrays are processed independently. + +The type of conversion is done with rounding and saturation, that is if the +result of scaling + conversion can not be represented exactly by a value of the +destination array element type, it is set to the nearest representable value on +the real axis. +@param src Source array +@param dst Destination array +@param scale Scale factor +@param shift Value added to the scaled source array elements + */ +CVAPI(void) +cvConvertScale(const CvArr *src, CvArr *dst, double scale CV_DEFAULT(1), + double shift CV_DEFAULT(0)); +#define cvCvtScale cvConvertScale +#define cvScale cvConvertScale +#define cvConvert(src, dst) cvConvertScale((src), (dst), 1, 0) + +/** Performs linear transformation on every source array element, + stores absolute value of the result: + dst(x,y,c) = abs(scale*src(x,y,c)+shift). + destination array must have 8u type. + In other cases one may use cvConvertScale + cvAbsDiffS */ +CVAPI(void) +cvConvertScaleAbs(const CvArr *src, CvArr *dst, double scale CV_DEFAULT(1), + double shift CV_DEFAULT(0)); +#define cvCvtScaleAbs cvConvertScaleAbs + +/** checks termination criteria validity and + sets eps to default_eps (if it is not set), + max_iter to default_max_iters (if it is not set) +*/ +CVAPI(CvTermCriteria) +cvCheckTermCriteria(CvTermCriteria criteria, double default_eps, + int default_max_iters); + +/****************************************************************************************\ +* Arithmetic, logic and comparison operations * +\****************************************************************************************/ + +/** dst(mask) = src1(mask) + src2(mask) */ +CVAPI(void) +cvAdd(const CvArr *src1, const CvArr *src2, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(mask) = src(mask) + value */ +CVAPI(void) +cvAddS(const CvArr *src, CvScalar value, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(mask) = src1(mask) - src2(mask) */ +CVAPI(void) +cvSub(const CvArr *src1, const CvArr *src2, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(mask) = src(mask) - value = src(mask) + (-value) */ +CV_INLINE void cvSubS(const CvArr *src, CvScalar value, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)) { + cvAddS(src, + cvScalar(-value.val[0], -value.val[1], -value.val[2], -value.val[3]), + dst, mask); +} + +/** dst(mask) = value - src(mask) */ +CVAPI(void) +cvSubRS(const CvArr *src, CvScalar value, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(idx) = src1(idx) * src2(idx) * scale + (scaled element-wise multiplication of 2 arrays) */ +CVAPI(void) +cvMul(const CvArr *src1, const CvArr *src2, CvArr *dst, + double scale CV_DEFAULT(1)); + +/** element-wise division/inversion with scaling: + dst(idx) = src1(idx) * scale / src2(idx) + or dst(idx) = scale / src2(idx) if src1 == 0 */ +CVAPI(void) +cvDiv(const CvArr *src1, const CvArr *src2, CvArr *dst, + double scale CV_DEFAULT(1)); + +/** dst = src1 * scale + src2 */ +CVAPI(void) +cvScaleAdd(const CvArr *src1, CvScalar scale, const CvArr *src2, CvArr *dst); +#define cvAXPY(A, real_scalar, B, C) \ + cvScaleAdd(A, cvRealScalar(real_scalar), B, C) + +/** dst = src1 * alpha + src2 * beta + gamma */ +CVAPI(void) +cvAddWeighted(const CvArr *src1, double alpha, const CvArr *src2, double beta, + double gamma, CvArr *dst); + +/** @brief Calculates the dot product of two arrays in Euclidean metrics. + +The function calculates and returns the Euclidean dot product of two arrays. + +\f[src1 \bullet src2 = \sum _I ( \texttt{src1} (I) \texttt{src2} (I))\f] + +In the case of multiple channel arrays, the results for all channels are +accumulated. In particular, cvDotProduct(a,a) where a is a complex vector, will +return \f$||\texttt{a}||^2\f$. The function can process multi-dimensional +arrays, row by row, layer by layer, and so on. +@param src1 The first source array +@param src2 The second source array + */ +CVAPI(double) cvDotProduct(const CvArr *src1, const CvArr *src2); + +/** dst(idx) = src1(idx) & src2(idx) */ +CVAPI(void) +cvAnd(const CvArr *src1, const CvArr *src2, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(idx) = src(idx) & value */ +CVAPI(void) +cvAndS(const CvArr *src, CvScalar value, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(idx) = src1(idx) | src2(idx) */ +CVAPI(void) +cvOr(const CvArr *src1, const CvArr *src2, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(idx) = src(idx) | value */ +CVAPI(void) +cvOrS(const CvArr *src, CvScalar value, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(idx) = src1(idx) ^ src2(idx) */ +CVAPI(void) +cvXor(const CvArr *src1, const CvArr *src2, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(idx) = src(idx) ^ value */ +CVAPI(void) +cvXorS(const CvArr *src, CvScalar value, CvArr *dst, + const CvArr *mask CV_DEFAULT(NULL)); + +/** dst(idx) = ~src(idx) */ +CVAPI(void) cvNot(const CvArr *src, CvArr *dst); + +/** dst(idx) = lower(idx) <= src(idx) < upper(idx) */ +CVAPI(void) +cvInRange(const CvArr *src, const CvArr *lower, const CvArr *upper, CvArr *dst); + +/** dst(idx) = lower <= src(idx) < upper */ +CVAPI(void) +cvInRangeS(const CvArr *src, CvScalar lower, CvScalar upper, CvArr *dst); + +#define CV_CMP_EQ 0 +#define CV_CMP_GT 1 +#define CV_CMP_GE 2 +#define CV_CMP_LT 3 +#define CV_CMP_LE 4 +#define CV_CMP_NE 5 + +/** The comparison operation support single-channel arrays only. + Destination image should be 8uC1 or 8sC1 */ + +/** dst(idx) = src1(idx) _cmp_op_ src2(idx) */ +CVAPI(void) cvCmp(const CvArr *src1, const CvArr *src2, CvArr *dst, int cmp_op); + +/** dst(idx) = src1(idx) _cmp_op_ value */ +CVAPI(void) cvCmpS(const CvArr *src, double value, CvArr *dst, int cmp_op); + +/** dst(idx) = min(src1(idx),src2(idx)) */ +CVAPI(void) cvMin(const CvArr *src1, const CvArr *src2, CvArr *dst); + +/** dst(idx) = max(src1(idx),src2(idx)) */ +CVAPI(void) cvMax(const CvArr *src1, const CvArr *src2, CvArr *dst); + +/** dst(idx) = min(src(idx),value) */ +CVAPI(void) cvMinS(const CvArr *src, double value, CvArr *dst); + +/** dst(idx) = max(src(idx),value) */ +CVAPI(void) cvMaxS(const CvArr *src, double value, CvArr *dst); + +/** dst(x,y,c) = abs(src1(x,y,c) - src2(x,y,c)) */ +CVAPI(void) cvAbsDiff(const CvArr *src1, const CvArr *src2, CvArr *dst); + +/** dst(x,y,c) = abs(src(x,y,c) - value(c)) */ +CVAPI(void) cvAbsDiffS(const CvArr *src, CvArr *dst, CvScalar value); +#define cvAbs(src, dst) cvAbsDiffS((src), (dst), cvScalarAll(0)) + +/****************************************************************************************\ +* Math operations * +\****************************************************************************************/ + +/** Does cartesian->polar coordinates conversion. + Either of output components (magnitude or angle) is optional */ +CVAPI(void) +cvCartToPolar(const CvArr *x, const CvArr *y, CvArr *magnitude, + CvArr *angle CV_DEFAULT(NULL), + int angle_in_degrees CV_DEFAULT(0)); + +/** Does polar->cartesian coordinates conversion. + Either of output components (magnitude or angle) is optional. + If magnitude is missing it is assumed to be all 1's */ +CVAPI(void) +cvPolarToCart(const CvArr *magnitude, const CvArr *angle, CvArr *x, CvArr *y, + int angle_in_degrees CV_DEFAULT(0)); + +/** Does powering: dst(idx) = src(idx)^power */ +CVAPI(void) cvPow(const CvArr *src, CvArr *dst, double power); + +/** Does exponention: dst(idx) = exp(src(idx)). + Overflow is not handled yet. Underflow is handled. + Maximal relative error is ~7e-6 for single-precision input */ +CVAPI(void) cvExp(const CvArr *src, CvArr *dst); + +/** Calculates natural logarithms: dst(idx) = log(abs(src(idx))). + Logarithm of 0 gives large negative number(~-700) + Maximal relative error is ~3e-7 for single-precision output +*/ +CVAPI(void) cvLog(const CvArr *src, CvArr *dst); + +/** Fast arctangent calculation */ +CVAPI(float) cvFastArctan(float y, float x); + +/** Fast cubic root calculation */ +CVAPI(float) cvCbrt(float value); + +#define CV_CHECK_RANGE 1 +#define CV_CHECK_QUIET 2 +/** Checks array values for NaNs, Infs or simply for too large numbers + (if CV_CHECK_RANGE is set). If CV_CHECK_QUIET is set, + no runtime errors is raised (function returns zero value in case of "bad" + values). Otherwise cvError is called */ +CVAPI(int) +cvCheckArr(const CvArr *arr, int flags CV_DEFAULT(0), + double min_val CV_DEFAULT(0), double max_val CV_DEFAULT(0)); +#define cvCheckArray cvCheckArr + +#define CV_RAND_UNI 0 +#define CV_RAND_NORMAL 1 + +/** @brief Fills an array with random numbers and updates the RNG state. + +The function fills the destination array with uniformly or normally distributed +random numbers. +@param rng CvRNG state initialized by cvRNG +@param arr The destination array +@param dist_type Distribution type +> - **CV_RAND_UNI** uniform distribution +> - **CV_RAND_NORMAL** normal or Gaussian distribution +@param param1 The first parameter of the distribution. In the case of a uniform +distribution it is the inclusive lower boundary of the random numbers range. In +the case of a normal distribution it is the mean value of the random numbers. +@param param2 The second parameter of the distribution. In the case of a uniform +distribution it is the exclusive upper boundary of the random numbers range. In +the case of a normal distribution it is the standard deviation of the random +numbers. +@sa randu, randn, RNG::fill. + */ +CVAPI(void) +cvRandArr(CvRNG *rng, CvArr *arr, int dist_type, CvScalar param1, + CvScalar param2); + +CVAPI(void) +cvRandShuffle(CvArr *mat, CvRNG *rng, double iter_factor CV_DEFAULT(1.)); + +#define CV_SORT_EVERY_ROW 0 +#define CV_SORT_EVERY_COLUMN 1 +#define CV_SORT_ASCENDING 0 +#define CV_SORT_DESCENDING 16 + +CVAPI(void) +cvSort(const CvArr *src, CvArr *dst CV_DEFAULT(NULL), + CvArr *idxmat CV_DEFAULT(NULL), int flags CV_DEFAULT(0)); + +/** Finds real roots of a cubic equation */ +CVAPI(int) cvSolveCubic(const CvMat *coeffs, CvMat *roots); + +/** Finds all real and complex roots of a polynomial equation */ +CVAPI(void) +cvSolvePoly(const CvMat *coeffs, CvMat *roots2, int maxiter CV_DEFAULT(20), + int fig CV_DEFAULT(100)); + +/****************************************************************************************\ +* Matrix operations * +\****************************************************************************************/ + +/** @brief Calculates the cross product of two 3D vectors. + +The function calculates the cross product of two 3D vectors: +\f[\texttt{dst} = \texttt{src1} \times \texttt{src2}\f] +or: +\f[\begin{array}{l} \texttt{dst} _1 = \texttt{src1} _2 \texttt{src2} _3 - +\texttt{src1} _3 \texttt{src2} _2 \\ \texttt{dst} _2 = \texttt{src1} _3 +\texttt{src2} _1 - \texttt{src1} _1 \texttt{src2} _3 \\ \texttt{dst} _3 = +\texttt{src1} _1 \texttt{src2} _2 - \texttt{src1} _2 \texttt{src2} _1 +\end{array}\f] +@param src1 The first source vector +@param src2 The second source vector +@param dst The destination vector + */ +CVAPI(void) cvCrossProduct(const CvArr *src1, const CvArr *src2, CvArr *dst); + +/** Matrix transform: dst = A*B + C, C is optional */ +#define cvMatMulAdd(src1, src2, src3, dst) \ + cvGEMM((src1), (src2), 1., (src3), 1., (dst), 0) +#define cvMatMul(src1, src2, dst) cvMatMulAdd((src1), (src2), NULL, (dst)) + +#define CV_GEMM_A_T 1 +#define CV_GEMM_B_T 2 +#define CV_GEMM_C_T 4 +/** Extended matrix transform: + dst = alpha*op(A)*op(B) + beta*op(C), where op(X) is X or X^T */ +CVAPI(void) +cvGEMM(const CvArr *src1, const CvArr *src2, double alpha, const CvArr *src3, + double beta, CvArr *dst, int tABC CV_DEFAULT(0)); +#define cvMatMulAddEx cvGEMM + +/** Transforms each element of source array and stores + resultant vectors in destination array */ +CVAPI(void) +cvTransform(const CvArr *src, CvArr *dst, const CvMat *transmat, + const CvMat *shiftvec CV_DEFAULT(NULL)); +#define cvMatMulAddS cvTransform + +/** Does perspective transform on every element of input array */ +CVAPI(void) +cvPerspectiveTransform(const CvArr *src, CvArr *dst, const CvMat *mat); + +/** Calculates (A-delta)*(A-delta)^T (order=0) or (A-delta)^T*(A-delta) + * (order=1) */ +CVAPI(void) +cvMulTransposed(const CvArr *src, CvArr *dst, int order, + const CvArr *delta CV_DEFAULT(NULL), + double scale CV_DEFAULT(1.)); + +/** Transposes matrix. Square matrices can be transposed in-place */ +CVAPI(void) cvTranspose(const CvArr *src, CvArr *dst); +#define cvT cvTranspose + +/** Completes the symmetric matrix from the lower (LtoR=0) or from the upper + * (LtoR!=0) part */ +CVAPI(void) cvCompleteSymm(CvMat *matrix, int LtoR CV_DEFAULT(0)); + +/** Mirror array data around horizontal (flip=0), + vertical (flip=1) or both(flip=-1) axises: + cvFlip(src) flips images vertically and sequences horizontally (inplace) */ +CVAPI(void) +cvFlip(const CvArr *src, CvArr *dst CV_DEFAULT(NULL), + int flip_mode CV_DEFAULT(0)); +#define cvMirror cvFlip + +#define CV_SVD_MODIFY_A 1 +#define CV_SVD_U_T 2 +#define CV_SVD_V_T 4 + +/** Performs Singular Value Decomposition of a matrix */ +CVAPI(void) +cvSVD(CvArr *A, CvArr *W, CvArr *U CV_DEFAULT(NULL), CvArr *V CV_DEFAULT(NULL), + int flags CV_DEFAULT(0)); + +/** Performs Singular Value Back Substitution (solves A*X = B): + flags must be the same as in cvSVD */ +CVAPI(void) +cvSVBkSb(const CvArr *W, const CvArr *U, const CvArr *V, const CvArr *B, + CvArr *X, int flags); + +#define CV_LU 0 +#define CV_SVD 1 +#define CV_SVD_SYM 2 +#define CV_CHOLESKY 3 +#define CV_QR 4 +#define CV_NORMAL 16 + +/** Inverts matrix */ +CVAPI(double) +cvInvert(const CvArr *src, CvArr *dst, int method CV_DEFAULT(CV_LU)); +#define cvInv cvInvert + +/** Solves linear system (src1)*(dst) = (src2) + (returns 0 if src1 is a singular and CV_LU method is used) */ +CVAPI(int) +cvSolve(const CvArr *src1, const CvArr *src2, CvArr *dst, + int method CV_DEFAULT(CV_LU)); + +/** Calculates determinant of input matrix */ +CVAPI(double) cvDet(const CvArr *mat); + +/** Calculates trace of the matrix (sum of elements on the main diagonal) */ +CVAPI(CvScalar) cvTrace(const CvArr *mat); + +/** Finds eigen values and vectors of a symmetric matrix */ +CVAPI(void) +cvEigenVV(CvArr *mat, CvArr *evects, CvArr *evals, double eps CV_DEFAULT(0), + int lowindex CV_DEFAULT(-1), int highindex CV_DEFAULT(-1)); + +///* Finds selected eigen values and vectors of a symmetric matrix */ +// CVAPI(void) cvSelectedEigenVV( CvArr* mat, CvArr* evects, CvArr* evals, +// int lowindex, int highindex ); + +/** Makes an identity matrix (mat_ij = i == j) */ +CVAPI(void) +cvSetIdentity(CvArr *mat, CvScalar value CV_DEFAULT(cvRealScalar(1))); + +/** Fills matrix with given range of numbers */ +CVAPI(CvArr *) cvRange(CvArr *mat, double start, double end); + +/** @anchor core_c_CovarFlags +@name Flags for cvCalcCovarMatrix +@see cvCalcCovarMatrix + @{ +*/ + +/** flag for cvCalcCovarMatrix, transpose([v1-avg, v2-avg,...]) * + * [v1-avg,v2-avg,...] */ +#define CV_COVAR_SCRAMBLED 0 + +/** flag for cvCalcCovarMatrix, [v1-avg, v2-avg,...] * + * transpose([v1-avg,v2-avg,...]) */ +#define CV_COVAR_NORMAL 1 + +/** flag for cvCalcCovarMatrix, do not calc average (i.e. mean vector) - use the + input vector instead (useful for calculating covariance matrix by parts) */ +#define CV_COVAR_USE_AVG 2 + +/** flag for cvCalcCovarMatrix, scale the covariance matrix coefficients by + * number of the vectors */ +#define CV_COVAR_SCALE 4 + +/** flag for cvCalcCovarMatrix, all the input vectors are stored in a single + * matrix, as its rows */ +#define CV_COVAR_ROWS 8 + +/** flag for cvCalcCovarMatrix, all the input vectors are stored in a single + * matrix, as its columns */ +#define CV_COVAR_COLS 16 + +/** @} */ + +/** Calculates covariation matrix for a set of vectors +@see @ref core_c_CovarFlags "flags" +*/ +CVAPI(void) +cvCalcCovarMatrix(const CvArr **vects, int count, CvArr *cov_mat, CvArr *avg, + int flags); + +#define CV_PCA_DATA_AS_ROW 0 +#define CV_PCA_DATA_AS_COL 1 +#define CV_PCA_USE_AVG 2 +CVAPI(void) +cvCalcPCA(const CvArr *data, CvArr *mean, CvArr *eigenvals, CvArr *eigenvects, + int flags); + +CVAPI(void) +cvProjectPCA(const CvArr *data, const CvArr *mean, const CvArr *eigenvects, + CvArr *result); + +CVAPI(void) +cvBackProjectPCA(const CvArr *proj, const CvArr *mean, const CvArr *eigenvects, + CvArr *result); + +/** Calculates Mahalanobis(weighted) distance */ +CVAPI(double) +cvMahalanobis(const CvArr *vec1, const CvArr *vec2, const CvArr *mat); +#define cvMahalonobis cvMahalanobis + +/****************************************************************************************\ +* Array Statistics * +\****************************************************************************************/ + +/** Finds sum of array elements */ +CVAPI(CvScalar) cvSum(const CvArr *arr); + +/** Calculates number of non-zero pixels */ +CVAPI(int) cvCountNonZero(const CvArr *arr); + +/** Calculates mean value of array elements */ +CVAPI(CvScalar) cvAvg(const CvArr *arr, const CvArr *mask CV_DEFAULT(NULL)); + +/** Calculates mean and standard deviation of pixel values */ +CVAPI(void) +cvAvgSdv(const CvArr *arr, CvScalar *mean, CvScalar *std_dev, + const CvArr *mask CV_DEFAULT(NULL)); + +/** Finds global minimum, maximum and their positions */ +CVAPI(void) +cvMinMaxLoc(const CvArr *arr, double *min_val, double *max_val, + CvPoint *min_loc CV_DEFAULT(NULL), + CvPoint *max_loc CV_DEFAULT(NULL), + const CvArr *mask CV_DEFAULT(NULL)); + +/** @anchor core_c_NormFlags + @name Flags for cvNorm and cvNormalize + @{ +*/ +#define CV_C 1 +#define CV_L1 2 +#define CV_L2 4 +#define CV_NORM_MASK 7 +#define CV_RELATIVE 8 +#define CV_DIFF 16 +#define CV_MINMAX 32 + +#define CV_DIFF_C (CV_DIFF | CV_C) +#define CV_DIFF_L1 (CV_DIFF | CV_L1) +#define CV_DIFF_L2 (CV_DIFF | CV_L2) +#define CV_RELATIVE_C (CV_RELATIVE | CV_C) +#define CV_RELATIVE_L1 (CV_RELATIVE | CV_L1) +#define CV_RELATIVE_L2 (CV_RELATIVE | CV_L2) +/** @} */ + +/** Finds norm, difference norm or relative difference norm for an array (or two +arrays) +@see ref core_c_NormFlags "flags" +*/ +CVAPI(double) +cvNorm(const CvArr *arr1, const CvArr *arr2 CV_DEFAULT(NULL), + int norm_type CV_DEFAULT(CV_L2), const CvArr *mask CV_DEFAULT(NULL)); + +/** @see ref core_c_NormFlags "flags" */ +CVAPI(void) +cvNormalize(const CvArr *src, CvArr *dst, double a CV_DEFAULT(1.), + double b CV_DEFAULT(0.), int norm_type CV_DEFAULT(CV_L2), + const CvArr *mask CV_DEFAULT(NULL)); + +/** @anchor core_c_ReduceFlags + @name Flags for cvReduce + @{ +*/ +#define CV_REDUCE_SUM 0 +#define CV_REDUCE_AVG 1 +#define CV_REDUCE_MAX 2 +#define CV_REDUCE_MIN 3 +/** @} */ + +/** @see @ref core_c_ReduceFlags "flags" */ +CVAPI(void) +cvReduce(const CvArr *src, CvArr *dst, int dim CV_DEFAULT(-1), + int op CV_DEFAULT(CV_REDUCE_SUM)); + +/****************************************************************************************\ +* Discrete Linear Transforms and Related Functions * +\****************************************************************************************/ + +/** @anchor core_c_DftFlags + @name Flags for cvDFT, cvDCT and cvMulSpectrums + @{ + */ +#define CV_DXT_FORWARD 0 +#define CV_DXT_INVERSE 1 +#define CV_DXT_SCALE 2 /**< divide result by size of array */ +#define CV_DXT_INV_SCALE (CV_DXT_INVERSE + CV_DXT_SCALE) +#define CV_DXT_INVERSE_SCALE CV_DXT_INV_SCALE +#define CV_DXT_ROWS 4 /**< transform each row individually */ +#define CV_DXT_MUL_CONJ \ + 8 /**< conjugate the second argument of cvMulSpectrums */ +/** @} */ + +/** Discrete Fourier Transform: + complex->complex, + real->ccs (forward), + ccs->real (inverse) +@see core_c_DftFlags "flags" +*/ +CVAPI(void) +cvDFT(const CvArr *src, CvArr *dst, int flags, int nonzero_rows CV_DEFAULT(0)); +#define cvFFT cvDFT + +/** Multiply results of DFTs: DFT(X)*DFT(Y) or DFT(X)*conj(DFT(Y)) +@see core_c_DftFlags "flags" +*/ +CVAPI(void) +cvMulSpectrums(const CvArr *src1, const CvArr *src2, CvArr *dst, int flags); + +/** Finds optimal DFT vector size >= size0 */ +CVAPI(int) cvGetOptimalDFTSize(int size0); + +/** Discrete Cosine Transform +@see core_c_DftFlags "flags" +*/ +CVAPI(void) cvDCT(const CvArr *src, CvArr *dst, int flags); + +/****************************************************************************************\ +* Dynamic data structures * +\****************************************************************************************/ + +/** Calculates length of sequence slice (with support of negative indices). */ +CVAPI(int) cvSliceLength(CvSlice slice, const CvSeq *seq); + +/** Creates new memory storage. + block_size == 0 means that default, + somewhat optimal size, is used (currently, it is 64K) */ +CVAPI(CvMemStorage *) cvCreateMemStorage(int block_size CV_DEFAULT(0)); + +/** Creates a memory storage that will borrow memory blocks from parent storage + */ +CVAPI(CvMemStorage *) cvCreateChildMemStorage(CvMemStorage *parent); + +/** Releases memory storage. All the children of a parent must be released + before the parent. A child storage returns all the blocks to parent when it + is released */ +CVAPI(void) cvReleaseMemStorage(CvMemStorage **storage); + +/** Clears memory storage. This is the only way(!!!) (besides + cvRestoreMemStoragePos) to reuse memory allocated for the storage - + cvClearSeq,cvClearSet ... do not free any memory. A child storage returns all + the blocks to the parent when it is cleared */ +CVAPI(void) cvClearMemStorage(CvMemStorage *storage); + +/** Remember a storage "free memory" position */ +CVAPI(void) +cvSaveMemStoragePos(const CvMemStorage *storage, CvMemStoragePos *pos); + +/** Restore a storage "free memory" position */ +CVAPI(void) cvRestoreMemStoragePos(CvMemStorage *storage, CvMemStoragePos *pos); + +/** Allocates continuous buffer of the specified size in the storage */ +CVAPI(void *) cvMemStorageAlloc(CvMemStorage *storage, size_t size); + +/** Allocates string in memory storage */ +// CVAPI(CvString) cvMemStorageAllocString( CvMemStorage* storage, const char* +// ptr, +// int len CV_DEFAULT(-1) ); + +/** Creates new empty sequence that will reside in the specified storage */ +CVAPI(CvSeq *) +cvCreateSeq(int seq_flags, size_t header_size, size_t elem_size, + CvMemStorage *storage); + +/** Changes default size (granularity) of sequence blocks. + The default size is ~1Kbyte */ +CVAPI(void) cvSetSeqBlockSize(CvSeq *seq, int delta_elems); + +/** Adds new element to the end of sequence. Returns pointer to the element */ +CVAPI(schar *) cvSeqPush(CvSeq *seq, const void *element CV_DEFAULT(NULL)); + +/** Adds new element to the beginning of sequence. Returns pointer to it */ +CVAPI(schar *) cvSeqPushFront(CvSeq *seq, const void *element CV_DEFAULT(NULL)); + +/** Removes the last element from sequence and optionally saves it */ +CVAPI(void) cvSeqPop(CvSeq *seq, void *element CV_DEFAULT(NULL)); + +/** Removes the first element from sequence and optioanally saves it */ +CVAPI(void) cvSeqPopFront(CvSeq *seq, void *element CV_DEFAULT(NULL)); + +#define CV_FRONT 1 +#define CV_BACK 0 +/** Adds several new elements to the end of sequence */ +CVAPI(void) +cvSeqPushMulti(CvSeq *seq, const void *elements, int count, + int in_front CV_DEFAULT(0)); + +/** Removes several elements from the end of sequence and optionally saves them + */ +CVAPI(void) +cvSeqPopMulti(CvSeq *seq, void *elements, int count, + int in_front CV_DEFAULT(0)); + +/** Inserts a new element in the middle of sequence. + cvSeqInsert(seq,0,elem) == cvSeqPushFront(seq,elem) */ +CVAPI(schar *) +cvSeqInsert(CvSeq *seq, int before_index, const void *element CV_DEFAULT(NULL)); + +/** Removes specified sequence element */ +CVAPI(void) cvSeqRemove(CvSeq *seq, int index); + +/** Removes all the elements from the sequence. The freed memory + can be reused later only by the same sequence unless cvClearMemStorage + or cvRestoreMemStoragePos is called */ +CVAPI(void) cvClearSeq(CvSeq *seq); + +/** Retrieves pointer to specified sequence element. + Negative indices are supported and mean counting from the end + (e.g -1 means the last sequence element) */ +CVAPI(schar *) cvGetSeqElem(const CvSeq *seq, int index); + +/** Calculates index of the specified sequence element. + Returns -1 if element does not belong to the sequence */ +CVAPI(int) +cvSeqElemIdx(const CvSeq *seq, const void *element, + CvSeqBlock **block CV_DEFAULT(NULL)); + +/** Initializes sequence writer. The new elements will be added to the end of + * sequence */ +CVAPI(void) cvStartAppendToSeq(CvSeq *seq, CvSeqWriter *writer); + +/** Combination of cvCreateSeq and cvStartAppendToSeq */ +CVAPI(void) +cvStartWriteSeq(int seq_flags, int header_size, int elem_size, + CvMemStorage *storage, CvSeqWriter *writer); + +/** Closes sequence writer, updates sequence header and returns pointer + to the resultant sequence + (which may be useful if the sequence was created using cvStartWriteSeq)) +*/ +CVAPI(CvSeq *) cvEndWriteSeq(CvSeqWriter *writer); + +/** Updates sequence header. May be useful to get access to some of previously + written elements via cvGetSeqElem or sequence reader */ +CVAPI(void) cvFlushSeqWriter(CvSeqWriter *writer); + +/** Initializes sequence reader. + The sequence can be read in forward or backward direction */ +CVAPI(void) +cvStartReadSeq(const CvSeq *seq, CvSeqReader *reader, + int reverse CV_DEFAULT(0)); + +/** Returns current sequence reader position (currently observed sequence + * element) */ +CVAPI(int) cvGetSeqReaderPos(CvSeqReader *reader); + +/** Changes sequence reader position. It may seek to an absolute or + to relative to the current position */ +CVAPI(void) +cvSetSeqReaderPos(CvSeqReader *reader, int index, + int is_relative CV_DEFAULT(0)); + +/** Copies sequence content to a continuous piece of memory */ +CVAPI(void *) +cvCvtSeqToArray(const CvSeq *seq, void *elements, + CvSlice slice CV_DEFAULT(CV_WHOLE_SEQ)); + +/** Creates sequence header for array. + After that all the operations on sequences that do not alter the content + can be applied to the resultant sequence */ +CVAPI(CvSeq *) +cvMakeSeqHeaderForArray(int seq_type, int header_size, int elem_size, + void *elements, int total, CvSeq *seq, + CvSeqBlock *block); + +/** Extracts sequence slice (with or without copying sequence elements) */ +CVAPI(CvSeq *) +cvSeqSlice(const CvSeq *seq, CvSlice slice, + CvMemStorage *storage CV_DEFAULT(NULL), int copy_data CV_DEFAULT(0)); + +CV_INLINE CvSeq *cvCloneSeq(const CvSeq *seq, + CvMemStorage *storage CV_DEFAULT(NULL)) { + return cvSeqSlice(seq, CV_WHOLE_SEQ, storage, 1); +} + +/** Removes sequence slice */ +CVAPI(void) cvSeqRemoveSlice(CvSeq *seq, CvSlice slice); + +/** Inserts a sequence or array into another sequence */ +CVAPI(void) +cvSeqInsertSlice(CvSeq *seq, int before_index, const CvArr *from_arr); + +/** a < b ? -1 : a > b ? 1 : 0 */ +typedef int(CV_CDECL *CvCmpFunc)(const void *a, const void *b, void *userdata); + +/** Sorts sequence in-place given element comparison function */ +CVAPI(void) +cvSeqSort(CvSeq *seq, CvCmpFunc func, void *userdata CV_DEFAULT(NULL)); + +/** Finds element in a [sorted] sequence */ +CVAPI(schar *) +cvSeqSearch(CvSeq *seq, const void *elem, CvCmpFunc func, int is_sorted, + int *elem_idx, void *userdata CV_DEFAULT(NULL)); + +/** Reverses order of sequence elements in-place */ +CVAPI(void) cvSeqInvert(CvSeq *seq); + +/** Splits sequence into one or more equivalence classes using the specified + * criteria */ +CVAPI(int) +cvSeqPartition(const CvSeq *seq, CvMemStorage *storage, CvSeq **labels, + CvCmpFunc is_equal, void *userdata); + +/************ Internal sequence functions ************/ +CVAPI(void) cvChangeSeqBlock(void *reader, int direction); +CVAPI(void) cvCreateSeqBlock(CvSeqWriter *writer); + +/** Creates a new set */ +CVAPI(CvSet *) +cvCreateSet(int set_flags, int header_size, int elem_size, + CvMemStorage *storage); + +/** Adds new element to the set and returns pointer to it */ +CVAPI(int) +cvSetAdd(CvSet *set_header, CvSetElem *elem CV_DEFAULT(NULL), + CvSetElem **inserted_elem CV_DEFAULT(NULL)); + +/** Fast variant of cvSetAdd */ +CV_INLINE CvSetElem *cvSetNew(CvSet *set_header) { + CvSetElem *elem = set_header->free_elems; + if (elem) { + set_header->free_elems = elem->next_free; + elem->flags = elem->flags & CV_SET_ELEM_IDX_MASK; + set_header->active_count++; + } else + cvSetAdd(set_header, NULL, &elem); + return elem; +} + +/** Removes set element given its pointer */ +CV_INLINE void cvSetRemoveByPtr(CvSet *set_header, void *elem) { + CvSetElem *_elem = (CvSetElem *)elem; + assert(_elem->flags >= + 0 /*&& (elem->flags & CV_SET_ELEM_IDX_MASK) < set_header->total*/); + _elem->next_free = set_header->free_elems; + _elem->flags = (_elem->flags & CV_SET_ELEM_IDX_MASK) | CV_SET_ELEM_FREE_FLAG; + set_header->free_elems = _elem; + set_header->active_count--; +} + +/** Removes element from the set by its index */ +CVAPI(void) cvSetRemove(CvSet *set_header, int index); + +/** Returns a set element by index. If the element doesn't belong to the set, + NULL is returned */ +CV_INLINE CvSetElem *cvGetSetElem(const CvSet *set_header, int idx) { + CvSetElem *elem = (CvSetElem *)(void *)cvGetSeqElem((CvSeq *)set_header, idx); + return elem && CV_IS_SET_ELEM(elem) ? elem : 0; +} + +/** Removes all the elements from the set */ +CVAPI(void) cvClearSet(CvSet *set_header); + +/** Creates new graph */ +CVAPI(CvGraph *) +cvCreateGraph(int graph_flags, int header_size, int vtx_size, int edge_size, + CvMemStorage *storage); + +/** Adds new vertex to the graph */ +CVAPI(int) +cvGraphAddVtx(CvGraph *graph, const CvGraphVtx *vtx CV_DEFAULT(NULL), + CvGraphVtx **inserted_vtx CV_DEFAULT(NULL)); + +/** Removes vertex from the graph together with all incident edges */ +CVAPI(int) cvGraphRemoveVtx(CvGraph *graph, int index); +CVAPI(int) cvGraphRemoveVtxByPtr(CvGraph *graph, CvGraphVtx *vtx); + +/** Link two vertices specified by indices or pointers if they + are not connected or return pointer to already existing edge + connecting the vertices. + Functions return 1 if a new edge was created, 0 otherwise */ +CVAPI(int) +cvGraphAddEdge(CvGraph *graph, int start_idx, int end_idx, + const CvGraphEdge *edge CV_DEFAULT(NULL), + CvGraphEdge **inserted_edge CV_DEFAULT(NULL)); + +CVAPI(int) +cvGraphAddEdgeByPtr(CvGraph *graph, CvGraphVtx *start_vtx, CvGraphVtx *end_vtx, + const CvGraphEdge *edge CV_DEFAULT(NULL), + CvGraphEdge **inserted_edge CV_DEFAULT(NULL)); + +/** Remove edge connecting two vertices */ +CVAPI(void) cvGraphRemoveEdge(CvGraph *graph, int start_idx, int end_idx); +CVAPI(void) +cvGraphRemoveEdgeByPtr(CvGraph *graph, CvGraphVtx *start_vtx, + CvGraphVtx *end_vtx); + +/** Find edge connecting two vertices */ +CVAPI(CvGraphEdge *) +cvFindGraphEdge(const CvGraph *graph, int start_idx, int end_idx); +CVAPI(CvGraphEdge *) +cvFindGraphEdgeByPtr(const CvGraph *graph, const CvGraphVtx *start_vtx, + const CvGraphVtx *end_vtx); +#define cvGraphFindEdge cvFindGraphEdge +#define cvGraphFindEdgeByPtr cvFindGraphEdgeByPtr + +/** Remove all vertices and edges from the graph */ +CVAPI(void) cvClearGraph(CvGraph *graph); + +/** Count number of edges incident to the vertex */ +CVAPI(int) cvGraphVtxDegree(const CvGraph *graph, int vtx_idx); +CVAPI(int) cvGraphVtxDegreeByPtr(const CvGraph *graph, const CvGraphVtx *vtx); + +/** Retrieves graph vertex by given index */ +#define cvGetGraphVtx(graph, idx) \ + (CvGraphVtx *)cvGetSetElem((CvSet *)(graph), (idx)) + +/** Retrieves index of a graph vertex given its pointer */ +#define cvGraphVtxIdx(graph, vtx) ((vtx)->flags & CV_SET_ELEM_IDX_MASK) + +/** Retrieves index of a graph edge given its pointer */ +#define cvGraphEdgeIdx(graph, edge) ((edge)->flags & CV_SET_ELEM_IDX_MASK) + +#define cvGraphGetVtxCount(graph) ((graph)->active_count) +#define cvGraphGetEdgeCount(graph) ((graph)->edges->active_count) + +#define CV_GRAPH_VERTEX 1 +#define CV_GRAPH_TREE_EDGE 2 +#define CV_GRAPH_BACK_EDGE 4 +#define CV_GRAPH_FORWARD_EDGE 8 +#define CV_GRAPH_CROSS_EDGE 16 +#define CV_GRAPH_ANY_EDGE 30 +#define CV_GRAPH_NEW_TREE 32 +#define CV_GRAPH_BACKTRACKING 64 +#define CV_GRAPH_OVER -1 + +#define CV_GRAPH_ALL_ITEMS -1 + +/** flags for graph vertices and edges */ +#define CV_GRAPH_ITEM_VISITED_FLAG (1 << 30) +#define CV_IS_GRAPH_VERTEX_VISITED(vtx) \ + (((CvGraphVtx *)(vtx))->flags & CV_GRAPH_ITEM_VISITED_FLAG) +#define CV_IS_GRAPH_EDGE_VISITED(edge) \ + (((CvGraphEdge *)(edge))->flags & CV_GRAPH_ITEM_VISITED_FLAG) +#define CV_GRAPH_SEARCH_TREE_NODE_FLAG (1 << 29) +#define CV_GRAPH_FORWARD_EDGE_FLAG (1 << 28) + +typedef struct CvGraphScanner { + CvGraphVtx *vtx; /* current graph vertex (or current edge origin) */ + CvGraphVtx *dst; /* current graph edge destination vertex */ + CvGraphEdge *edge; /* current edge */ + + CvGraph *graph; /* the graph */ + CvSeq *stack; /* the graph vertex stack */ + int index; /* the lower bound of certainly visited vertices */ + int mask; /* event mask */ +} CvGraphScanner; + +/** Creates new graph scanner. */ +CVAPI(CvGraphScanner *) +cvCreateGraphScanner(CvGraph *graph, CvGraphVtx *vtx CV_DEFAULT(NULL), + int mask CV_DEFAULT(CV_GRAPH_ALL_ITEMS)); + +/** Releases graph scanner. */ +CVAPI(void) cvReleaseGraphScanner(CvGraphScanner **scanner); + +/** Get next graph element */ +CVAPI(int) cvNextGraphItem(CvGraphScanner *scanner); + +/** Creates a copy of graph */ +CVAPI(CvGraph *) cvCloneGraph(const CvGraph *graph, CvMemStorage *storage); + +/** Does look-up transformation. Elements of the source array + (that should be 8uC1 or 8sC1) are used as indexes in lutarr 256-element table + */ +CVAPI(void) cvLUT(const CvArr *src, CvArr *dst, const CvArr *lut); + +/******************* Iteration through the sequence tree *****************/ +typedef struct CvTreeNodeIterator { + const void *node; + int level; + int max_level; +} CvTreeNodeIterator; + +CVAPI(void) +cvInitTreeNodeIterator(CvTreeNodeIterator *tree_iterator, const void *first, + int max_level); +CVAPI(void *) cvNextTreeNode(CvTreeNodeIterator *tree_iterator); +CVAPI(void *) cvPrevTreeNode(CvTreeNodeIterator *tree_iterator); + +/** Inserts sequence into tree with specified "parent" sequence. + If parent is equal to frame (e.g. the most external contour), + then added contour will have null pointer to parent. */ +CVAPI(void) cvInsertNodeIntoTree(void *node, void *parent, void *frame); + +/** Removes contour from tree (together with the contour children). */ +CVAPI(void) cvRemoveNodeFromTree(void *node, void *frame); + +/** Gathers pointers to all the sequences, + accessible from the `first`, to the single sequence */ +CVAPI(CvSeq *) +cvTreeToNodeSeq(const void *first, int header_size, CvMemStorage *storage); + +/** The function implements the K-means algorithm for clustering an array of + sample vectors in a specified number of classes */ +#define CV_KMEANS_USE_INITIAL_LABELS 1 +CVAPI(int) +cvKMeans2(const CvArr *samples, int cluster_count, CvArr *labels, + CvTermCriteria termcrit, int attempts CV_DEFAULT(1), + CvRNG *rng CV_DEFAULT(0), int flags CV_DEFAULT(0), + CvArr *_centers CV_DEFAULT(0), double *compactness CV_DEFAULT(0)); + +/****************************************************************************************\ +* System functions * +\****************************************************************************************/ + +/** Loads optimized functions from IPP, MKL etc. or switches back to pure C code + */ +CVAPI(int) cvUseOptimized(int on_off); + +typedef IplImage *(CV_STDCALL *Cv_iplCreateImageHeader)(int, int, int, char *, + char *, int, int, int, + int, int, IplROI *, + IplImage *, void *, + IplTileInfo *); +typedef void(CV_STDCALL *Cv_iplAllocateImageData)(IplImage *, int, int); +typedef void(CV_STDCALL *Cv_iplDeallocate)(IplImage *, int); +typedef IplROI *(CV_STDCALL *Cv_iplCreateROI)(int, int, int, int, int); +typedef IplImage *(CV_STDCALL *Cv_iplCloneImage)(const IplImage *); + +/** @brief Makes OpenCV use IPL functions for allocating IplImage and IplROI +structures. + +Normally, the function is not called directly. Instead, a simple macro +CV_TURN_ON_IPL_COMPATIBILITY() is used that calls cvSetIPLAllocators and passes +there pointers to IPL allocation functions. : +@code + ... + CV_TURN_ON_IPL_COMPATIBILITY() + ... +@endcode +@param create_header pointer to a function, creating IPL image header. +@param allocate_data pointer to a function, allocating IPL image data. +@param deallocate pointer to a function, deallocating IPL image. +@param create_roi pointer to a function, creating IPL image ROI (i.e. Region of +Interest). +@param clone_image pointer to a function, cloning an IPL image. + */ +CVAPI(void) +cvSetIPLAllocators(Cv_iplCreateImageHeader create_header, + Cv_iplAllocateImageData allocate_data, + Cv_iplDeallocate deallocate, Cv_iplCreateROI create_roi, + Cv_iplCloneImage clone_image); + +#define CV_TURN_ON_IPL_COMPATIBILITY() \ + cvSetIPLAllocators(iplCreateImageHeader, iplAllocateImage, iplDeallocate, \ + iplCreateROI, iplCloneImage) + +/****************************************************************************************\ +* Data Persistence * +\****************************************************************************************/ + +#if 0 +/********************************** High-level functions ********************************/ + +/** @brief Opens file storage for reading or writing data. + +The function opens file storage for reading or writing data. In the latter case, a new file is +created or an existing file is rewritten. The type of the read or written file is determined by the +filename extension: .xml for XML, .yml or .yaml for YAML and .json for JSON. + +At the same time, it also supports adding parameters like "example.xml?base64". + +The function returns a pointer to the CvFileStorage structure. +If the file cannot be opened then the function returns NULL. +@param filename Name of the file associated with the storage +@param memstorage Memory storage used for temporary data and for +: storing dynamic structures, such as CvSeq or CvGraph . If it is NULL, a temporary memory + storage is created and used. +@param flags Can be one of the following: +> - **CV_STORAGE_READ** the storage is open for reading +> - **CV_STORAGE_WRITE** the storage is open for writing + (use **CV_STORAGE_WRITE | CV_STORAGE_WRITE_BASE64** to write rawdata in Base64) +@param encoding + */ +CVAPI(CvFileStorage*) cvOpenFileStorage( const char* filename, CvMemStorage* memstorage, + int flags, const char* encoding CV_DEFAULT(NULL) ); + +/** @brief Releases file storage. + +The function closes the file associated with the storage and releases all the temporary structures. +It must be called after all I/O operations with the storage are finished. +@param fs Double pointer to the released file storage + */ +CVAPI(void) cvReleaseFileStorage( CvFileStorage** fs ); + +/** returns attribute value or 0 (NULL) if there is no such attribute */ +CVAPI(const char*) cvAttrValue( const CvAttrList* attr, const char* attr_name ); + +/** @brief Starts writing a new structure. + +The function starts writing a compound structure (collection) that can be a sequence or a map. After +all the structure fields, which can be scalars or structures, are written, cvEndWriteStruct should +be called. The function can be used to group some objects or to implement the write function for a +some user object (see CvTypeInfo). +@param fs File storage +@param name Name of the written structure. The structure can be accessed by this name when the +storage is read. +@param struct_flags A combination one of the following values: +- **CV_NODE_SEQ** the written structure is a sequence (see discussion of CvFileStorage ), + that is, its elements do not have a name. +- **CV_NODE_MAP** the written structure is a map (see discussion of CvFileStorage ), that + is, all its elements have names. +One and only one of the two above flags must be specified +- **CV_NODE_FLOW** the optional flag that makes sense only for YAML streams. It means that + the structure is written as a flow (not as a block), which is more compact. It is + recommended to use this flag for structures or arrays whose elements are all scalars. +@param type_name Optional parameter - the object type name. In + case of XML it is written as a type_id attribute of the structure opening tag. In the case of + YAML it is written after a colon following the structure name (see the example in + CvFileStorage description). In case of JSON it is written as a name/value pair. + Mainly it is used with user objects. When the storage is read, the + encoded type name is used to determine the object type (see CvTypeInfo and cvFindType ). +@param attributes This parameter is not used in the current implementation + */ +CVAPI(void) cvStartWriteStruct( CvFileStorage* fs, const char* name, + int struct_flags, const char* type_name CV_DEFAULT(NULL), + CvAttrList attributes CV_DEFAULT(cvAttrList())); + +/** @brief Finishes writing to a file node collection. +@param fs File storage +@sa cvStartWriteStruct. + */ +CVAPI(void) cvEndWriteStruct( CvFileStorage* fs ); + +/** @brief Writes an integer value. + +The function writes a single integer value (with or without a name) to the file storage. +@param fs File storage +@param name Name of the written value. Should be NULL if and only if the parent structure is a +sequence. +@param value The written value + */ +CVAPI(void) cvWriteInt( CvFileStorage* fs, const char* name, int value ); + +/** @brief Writes a floating-point value. + +The function writes a single floating-point value (with or without a name) to file storage. Special +values are encoded as follows: NaN (Not A Number) as .NaN, infinity as +.Inf or -.Inf. + +The following example shows how to use the low-level writing functions to store custom structures, +such as termination criteria, without registering a new type. : +@code + void write_termcriteria( CvFileStorage* fs, const char* struct_name, + CvTermCriteria* termcrit ) + { + cvStartWriteStruct( fs, struct_name, CV_NODE_MAP, NULL, cvAttrList(0,0)); + cvWriteComment( fs, "termination criteria", 1 ); // just a description + if( termcrit->type & CV_TERMCRIT_ITER ) + cvWriteInteger( fs, "max_iterations", termcrit->max_iter ); + if( termcrit->type & CV_TERMCRIT_EPS ) + cvWriteReal( fs, "accuracy", termcrit->epsilon ); + cvEndWriteStruct( fs ); + } +@endcode +@param fs File storage +@param name Name of the written value. Should be NULL if and only if the parent structure is a +sequence. +@param value The written value +*/ +CVAPI(void) cvWriteReal( CvFileStorage* fs, const char* name, double value ); + +/** @brief Writes a text string. + +The function writes a text string to file storage. +@param fs File storage +@param name Name of the written string . Should be NULL if and only if the parent structure is a +sequence. +@param str The written text string +@param quote If non-zero, the written string is put in quotes, regardless of whether they are +required. Otherwise, if the flag is zero, quotes are used only when they are required (e.g. when +the string starts with a digit or contains spaces). + */ +CVAPI(void) cvWriteString( CvFileStorage* fs, const char* name, + const char* str, int quote CV_DEFAULT(0) ); + +/** @brief Writes a comment. + +The function writes a comment into file storage. The comments are skipped when the storage is read. +@param fs File storage +@param comment The written comment, single-line or multi-line +@param eol_comment If non-zero, the function tries to put the comment at the end of current line. +If the flag is zero, if the comment is multi-line, or if it does not fit at the end of the current +line, the comment starts a new line. + */ +CVAPI(void) cvWriteComment( CvFileStorage* fs, const char* comment, + int eol_comment ); + +/** @brief Writes an object to file storage. + +The function writes an object to file storage. First, the appropriate type info is found using +cvTypeOf. Then, the write method associated with the type info is called. + +Attributes are used to customize the writing procedure. The standard types support the following +attributes (all the dt attributes have the same format as in cvWriteRawData): + +-# CvSeq + - **header_dt** description of user fields of the sequence header that follow CvSeq, or + CvChain (if the sequence is a Freeman chain) or CvContour (if the sequence is a contour or + point sequence) + - **dt** description of the sequence elements. + - **recursive** if the attribute is present and is not equal to "0" or "false", the whole + tree of sequences (contours) is stored. +-# CvGraph + - **header_dt** description of user fields of the graph header that follows CvGraph; + - **vertex_dt** description of user fields of graph vertices + - **edge_dt** description of user fields of graph edges (note that the edge weight is + always written, so there is no need to specify it explicitly) + +Below is the code that creates the YAML file shown in the CvFileStorage description: +@code + #include "cxcore.h" + + int main( int argc, char** argv ) + { + CvMat* mat = cvCreateMat( 3, 3, CV_32F ); + CvFileStorage* fs = cvOpenFileStorage( "example.yml", 0, CV_STORAGE_WRITE ); + + cvSetIdentity( mat ); + cvWrite( fs, "A", mat, cvAttrList(0,0) ); + + cvReleaseFileStorage( &fs ); + cvReleaseMat( &mat ); + return 0; + } +@endcode +@param fs File storage +@param name Name of the written object. Should be NULL if and only if the parent structure is a +sequence. +@param ptr Pointer to the object +@param attributes The attributes of the object. They are specific for each particular type (see +the discussion below). + */ +CVAPI(void) cvWrite( CvFileStorage* fs, const char* name, const void* ptr, + CvAttrList attributes CV_DEFAULT(cvAttrList())); + +/** @brief Starts the next stream. + +The function finishes the currently written stream and starts the next stream. In the case of XML +the file with multiple streams looks like this: +@code{.xml} + + + + + + + ... +@endcode +The YAML file will look like this: +@code{.yaml} + %YAML 1.0 + # stream #1 data + ... + --- + # stream #2 data +@endcode +This is useful for concatenating files or for resuming the writing process. +@param fs File storage + */ +CVAPI(void) cvStartNextStream( CvFileStorage* fs ); + +/** @brief Writes multiple numbers. + +The function writes an array, whose elements consist of single or multiple numbers. The function +call can be replaced with a loop containing a few cvWriteInt and cvWriteReal calls, but a single +call is more efficient. Note that because none of the elements have a name, they should be written +to a sequence rather than a map. +@param fs File storage +@param src Pointer to the written array +@param len Number of the array elements to write +@param dt Specification of each array element, see @ref format_spec "format specification" + */ +CVAPI(void) cvWriteRawData( CvFileStorage* fs, const void* src, + int len, const char* dt ); + +/** @brief Writes multiple numbers in Base64. + +If either CV_STORAGE_WRITE_BASE64 or cv::FileStorage::WRITE_BASE64 is used, +this function will be the same as cvWriteRawData. If neither, the main +difference is that it outputs a sequence in Base64 encoding rather than +in plain text. + +This function can only be used to write a sequence with a type "binary". + +@param fs File storage +@param src Pointer to the written array +@param len Number of the array elements to write +@param dt Specification of each array element, see @ref format_spec "format specification" +*/ +CVAPI(void) cvWriteRawDataBase64( CvFileStorage* fs, const void* src, + int len, const char* dt ); + +/** @brief Returns a unique pointer for a given name. + +The function returns a unique pointer for each particular file node name. This pointer can be then +passed to the cvGetFileNode function that is faster than cvGetFileNodeByName because it compares +text strings by comparing pointers rather than the strings' content. + +Consider the following example where an array of points is encoded as a sequence of 2-entry maps: +@code + points: + - { x: 10, y: 10 } + - { x: 20, y: 20 } + - { x: 30, y: 30 } + # ... +@endcode +Then, it is possible to get hashed "x" and "y" pointers to speed up decoding of the points. : +@code + #include "cxcore.h" + + int main( int argc, char** argv ) + { + CvFileStorage* fs = cvOpenFileStorage( "points.yml", 0, CV_STORAGE_READ ); + CvStringHashNode* x_key = cvGetHashedNode( fs, "x", -1, 1 ); + CvStringHashNode* y_key = cvGetHashedNode( fs, "y", -1, 1 ); + CvFileNode* points = cvGetFileNodeByName( fs, 0, "points" ); + + if( CV_NODE_IS_SEQ(points->tag) ) + { + CvSeq* seq = points->data.seq; + int i, total = seq->total; + CvSeqReader reader; + cvStartReadSeq( seq, &reader, 0 ); + for( i = 0; i < total; i++ ) + { + CvFileNode* pt = (CvFileNode*)reader.ptr; + #if 1 // faster variant + CvFileNode* xnode = cvGetFileNode( fs, pt, x_key, 0 ); + CvFileNode* ynode = cvGetFileNode( fs, pt, y_key, 0 ); + assert( xnode && CV_NODE_IS_INT(xnode->tag) && + ynode && CV_NODE_IS_INT(ynode->tag)); + int x = xnode->data.i; // or x = cvReadInt( xnode, 0 ); + int y = ynode->data.i; // or y = cvReadInt( ynode, 0 ); + #elif 1 // slower variant; does not use x_key & y_key + CvFileNode* xnode = cvGetFileNodeByName( fs, pt, "x" ); + CvFileNode* ynode = cvGetFileNodeByName( fs, pt, "y" ); + assert( xnode && CV_NODE_IS_INT(xnode->tag) && + ynode && CV_NODE_IS_INT(ynode->tag)); + int x = xnode->data.i; // or x = cvReadInt( xnode, 0 ); + int y = ynode->data.i; // or y = cvReadInt( ynode, 0 ); + #else // the slowest yet the easiest to use variant + int x = cvReadIntByName( fs, pt, "x", 0 ); + int y = cvReadIntByName( fs, pt, "y", 0 ); + #endif + CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); + printf(" + } + } + cvReleaseFileStorage( &fs ); + return 0; + } +@endcode +Please note that whatever method of accessing a map you are using, it is still much slower than +using plain sequences; for example, in the above example, it is more efficient to encode the points +as pairs of integers in a single numeric sequence. +@param fs File storage +@param name Literal node name +@param len Length of the name (if it is known apriori), or -1 if it needs to be calculated +@param create_missing Flag that specifies, whether an absent key should be added into the hash table +*/ +CVAPI(CvStringHashNode*) cvGetHashedKey( CvFileStorage* fs, const char* name, + int len CV_DEFAULT(-1), + int create_missing CV_DEFAULT(0)); + +/** @brief Retrieves one of the top-level nodes of the file storage. + +The function returns one of the top-level file nodes. The top-level nodes do not have a name, they +correspond to the streams that are stored one after another in the file storage. If the index is out +of range, the function returns a NULL pointer, so all the top-level nodes can be iterated by +subsequent calls to the function with stream_index=0,1,..., until the NULL pointer is returned. +This function can be used as a base for recursive traversal of the file storage. +@param fs File storage +@param stream_index Zero-based index of the stream. See cvStartNextStream . In most cases, +there is only one stream in the file; however, there can be several. + */ +CVAPI(CvFileNode*) cvGetRootFileNode( const CvFileStorage* fs, + int stream_index CV_DEFAULT(0) ); + +/** @brief Finds a node in a map or file storage. + +The function finds a file node. It is a faster version of cvGetFileNodeByName (see +cvGetHashedKey discussion). Also, the function can insert a new node, if it is not in the map yet. +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. If both map and +key are NULLs, the function returns the root file node - a map that contains top-level nodes. +@param key Unique pointer to the node name, retrieved with cvGetHashedKey +@param create_missing Flag that specifies whether an absent node should be added to the map + */ +CVAPI(CvFileNode*) cvGetFileNode( CvFileStorage* fs, CvFileNode* map, + const CvStringHashNode* key, + int create_missing CV_DEFAULT(0) ); + +/** @brief Finds a node in a map or file storage. + +The function finds a file node by name. The node is searched either in map or, if the pointer is +NULL, among the top-level file storage nodes. Using this function for maps and cvGetSeqElem (or +sequence reader) for sequences, it is possible to navigate through the file storage. To speed up +multiple queries for a certain key (e.g., in the case of an array of structures) one may use a +combination of cvGetHashedKey and cvGetFileNode. +@param fs File storage +@param map The parent map. If it is NULL, the function searches in all the top-level nodes +(streams), starting with the first one. +@param name The file node name + */ +CVAPI(CvFileNode*) cvGetFileNodeByName( const CvFileStorage* fs, + const CvFileNode* map, + const char* name ); + +/** @brief Retrieves an integer value from a file node. + +The function returns an integer that is represented by the file node. If the file node is NULL, the +default_value is returned (thus, it is convenient to call the function right after cvGetFileNode +without checking for a NULL pointer). If the file node has type CV_NODE_INT, then node-\>data.i is +returned. If the file node has type CV_NODE_REAL, then node-\>data.f is converted to an integer +and returned. Otherwise the error is reported. +@param node File node +@param default_value The value that is returned if node is NULL + */ +CV_INLINE int cvReadInt( const CvFileNode* node, int default_value CV_DEFAULT(0) ) +{ + return !node ? default_value : + CV_NODE_IS_INT(node->tag) ? node->data.i : + CV_NODE_IS_REAL(node->tag) ? cvRound(node->data.f) : 0x7fffffff; +} + +/** @brief Finds a file node and returns its value. + +The function is a simple superposition of cvGetFileNodeByName and cvReadInt. +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. +@param name The node name +@param default_value The value that is returned if the file node is not found + */ +CV_INLINE int cvReadIntByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, int default_value CV_DEFAULT(0) ) +{ + return cvReadInt( cvGetFileNodeByName( fs, map, name ), default_value ); +} + +/** @brief Retrieves a floating-point value from a file node. + +The function returns a floating-point value that is represented by the file node. If the file node +is NULL, the default_value is returned (thus, it is convenient to call the function right after +cvGetFileNode without checking for a NULL pointer). If the file node has type CV_NODE_REAL , +then node-\>data.f is returned. If the file node has type CV_NODE_INT , then node-:math:\>data.f +is converted to floating-point and returned. Otherwise the result is not determined. +@param node File node +@param default_value The value that is returned if node is NULL + */ +CV_INLINE double cvReadReal( const CvFileNode* node, double default_value CV_DEFAULT(0.) ) +{ + return !node ? default_value : + CV_NODE_IS_INT(node->tag) ? (double)node->data.i : + CV_NODE_IS_REAL(node->tag) ? node->data.f : 1e300; +} + +/** @brief Finds a file node and returns its value. + +The function is a simple superposition of cvGetFileNodeByName and cvReadReal . +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. +@param name The node name +@param default_value The value that is returned if the file node is not found + */ +CV_INLINE double cvReadRealByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, double default_value CV_DEFAULT(0.) ) +{ + return cvReadReal( cvGetFileNodeByName( fs, map, name ), default_value ); +} + +/** @brief Retrieves a text string from a file node. + +The function returns a text string that is represented by the file node. If the file node is NULL, +the default_value is returned (thus, it is convenient to call the function right after +cvGetFileNode without checking for a NULL pointer). If the file node has type CV_NODE_STR , then +node-:math:\>data.str.ptr is returned. Otherwise the result is not determined. +@param node File node +@param default_value The value that is returned if node is NULL + */ +CV_INLINE const char* cvReadString( const CvFileNode* node, + const char* default_value CV_DEFAULT(NULL) ) +{ + return !node ? default_value : CV_NODE_IS_STRING(node->tag) ? node->data.str.ptr : 0; +} + +/** @brief Finds a file node by its name and returns its value. + +The function is a simple superposition of cvGetFileNodeByName and cvReadString . +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. +@param name The node name +@param default_value The value that is returned if the file node is not found + */ +CV_INLINE const char* cvReadStringByName( const CvFileStorage* fs, const CvFileNode* map, + const char* name, const char* default_value CV_DEFAULT(NULL) ) +{ + return cvReadString( cvGetFileNodeByName( fs, map, name ), default_value ); +} + + +/** @brief Decodes an object and returns a pointer to it. + +The function decodes a user object (creates an object in a native representation from the file +storage subtree) and returns it. The object to be decoded must be an instance of a registered type +that supports the read method (see CvTypeInfo). The type of the object is determined by the type +name that is encoded in the file. If the object is a dynamic structure, it is created either in +memory storage and passed to cvOpenFileStorage or, if a NULL pointer was passed, in temporary +memory storage, which is released when cvReleaseFileStorage is called. Otherwise, if the object is +not a dynamic structure, it is created in a heap and should be released with a specialized function +or by using the generic cvRelease. +@param fs File storage +@param node The root object node +@param attributes Unused parameter + */ +CVAPI(void*) cvRead( CvFileStorage* fs, CvFileNode* node, + CvAttrList* attributes CV_DEFAULT(NULL)); + +/** @brief Finds an object by name and decodes it. + +The function is a simple superposition of cvGetFileNodeByName and cvRead. +@param fs File storage +@param map The parent map. If it is NULL, the function searches a top-level node. +@param name The node name +@param attributes Unused parameter + */ +CV_INLINE void* cvReadByName( CvFileStorage* fs, const CvFileNode* map, + const char* name, CvAttrList* attributes CV_DEFAULT(NULL) ) +{ + return cvRead( fs, cvGetFileNodeByName( fs, map, name ), attributes ); +} + + +/** @brief Initializes the file node sequence reader. + +The function initializes the sequence reader to read data from a file node. The initialized reader +can be then passed to cvReadRawDataSlice. +@param fs File storage +@param src The file node (a sequence) to read numbers from +@param reader Pointer to the sequence reader + */ +CVAPI(void) cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, + CvSeqReader* reader ); + +/** @brief Initializes file node sequence reader. + +The function reads one or more elements from the file node, representing a sequence, to a +user-specified array. The total number of read sequence elements is a product of total and the +number of components in each array element. For example, if dt=2if, the function will read total\*3 +sequence elements. As with any sequence, some parts of the file node sequence can be skipped or read +repeatedly by repositioning the reader using cvSetSeqReaderPos. +@param fs File storage +@param reader The sequence reader. Initialize it with cvStartReadRawData . +@param count The number of elements to read +@param dst Pointer to the destination array +@param dt Specification of each array element. It has the same format as in cvWriteRawData . + */ +CVAPI(void) cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, + int count, void* dst, const char* dt ); + +/** @brief Reads multiple numbers. + +The function reads elements from a file node that represents a sequence of scalars. +@param fs File storage +@param src The file node (a sequence) to read numbers from +@param dst Pointer to the destination array +@param dt Specification of each array element. It has the same format as in cvWriteRawData . + */ +CVAPI(void) cvReadRawData( const CvFileStorage* fs, const CvFileNode* src, + void* dst, const char* dt ); + +/** @brief Writes a file node to another file storage. + +The function writes a copy of a file node to file storage. Possible applications of the function are +merging several file storages into one and conversion between XML, YAML and JSON formats. +@param fs Destination file storage +@param new_node_name New name of the file node in the destination file storage. To keep the +existing name, use cvcvGetFileNodeName +@param node The written node +@param embed If the written node is a collection and this parameter is not zero, no extra level of +hierarchy is created. Instead, all the elements of node are written into the currently written +structure. Of course, map elements can only be embedded into another map, and sequence elements +can only be embedded into another sequence. + */ +CVAPI(void) cvWriteFileNode( CvFileStorage* fs, const char* new_node_name, + const CvFileNode* node, int embed ); + +/** @brief Returns the name of a file node. + +The function returns the name of a file node or NULL, if the file node does not have a name or if +node is NULL. +@param node File node + */ +CVAPI(const char*) cvGetFileNodeName( const CvFileNode* node ); + +/*********************************** Adding own types ***********************************/ + +/** @brief Registers a new type. + +The function registers a new type, which is described by info . The function creates a copy of the +structure, so the user should delete it after calling the function. +@param info Type info structure + */ +CVAPI(void) cvRegisterType( const CvTypeInfo* info ); + +/** @brief Unregisters the type. + +The function unregisters a type with a specified name. If the name is unknown, it is possible to +locate the type info by an instance of the type using cvTypeOf or by iterating the type list, +starting from cvFirstType, and then calling cvUnregisterType(info-\>typeName). +@param type_name Name of an unregistered type + */ +CVAPI(void) cvUnregisterType( const char* type_name ); + +/** @brief Returns the beginning of a type list. + +The function returns the first type in the list of registered types. Navigation through the list can +be done via the prev and next fields of the CvTypeInfo structure. + */ +CVAPI(CvTypeInfo*) cvFirstType(void); + +/** @brief Finds a type by its name. + +The function finds a registered type by its name. It returns NULL if there is no type with the +specified name. +@param type_name Type name + */ +CVAPI(CvTypeInfo*) cvFindType( const char* type_name ); + +/** @brief Returns the type of an object. + +The function finds the type of a given object. It iterates through the list of registered types and +calls the is_instance function/method for every type info structure with that object until one of +them returns non-zero or until the whole list has been traversed. In the latter case, the function +returns NULL. +@param struct_ptr The object pointer + */ +CVAPI(CvTypeInfo*) cvTypeOf( const void* struct_ptr ); + +#endif + +/** @brief Releases an object. + + The function finds the type of a given object and calls release with the double + pointer. + @param struct_ptr Double pointer to the object + */ +CVAPI(void) cvRelease(void **struct_ptr); + +/** @brief Makes a clone of an object. + +The function finds the type of a given object and calls clone with the passed +object. Of course, if you know the object type, for example, struct_ptr is +CvMat\*, it is faster to call the specific function, like cvCloneMat. +@param struct_ptr The object to clone + */ +CVAPI(void *) cvClone(const void *struct_ptr); + +/*********************************** Measuring Execution Time + * ***************************/ + +/** helper functions for RNG initialization and accurate time measurement: + uses internal clock counter on x86 */ +CVAPI(int64) cvGetTickCount(void); +CVAPI(double) cvGetTickFrequency(void); + +/*********************************** CPU capabilities + * ***********************************/ + +CVAPI(int) cvCheckHardwareSupport(int feature); + +/*********************************** Multi-Threading + * ************************************/ + +/** retrieve/set the number of threads used in OpenMP implementations */ +CVAPI(int) cvGetNumThreads(void); +CVAPI(void) cvSetNumThreads(int threads CV_DEFAULT(0)); +/** get index of the thread being executed */ +CVAPI(int) cvGetThreadNum(void); + +/********************************** Error Handling + * **************************************/ + +/** Get current OpenCV error status */ +CVAPI(int) cvGetErrStatus(void); + +/** Sets error status silently */ +CVAPI(void) cvSetErrStatus(int status); + +#define CV_ErrModeLeaf 0 /* Print error and exit program */ +#define CV_ErrModeParent 1 /* Print error and continue */ +#define CV_ErrModeSilent 2 /* Don't print and continue */ + +/** Retrieves current error processing mode */ +CVAPI(int) cvGetErrMode(void); + +/** Sets error processing mode, returns previously used mode */ +CVAPI(int) cvSetErrMode(int mode); + +/** Sets error status and performs some additional actions (displaying message + box, writing message to stderr, terminating application etc.) depending on the + current error mode */ +CVAPI(void) +cvError(int status, const char *func_name, const char *err_msg, + const char *file_name, int line); + +/** Retrieves textual description of the error given its code */ +CVAPI(const char *) cvErrorStr(int status); + +/** Retrieves detailed information about the last error occurred */ +CVAPI(int) +cvGetErrInfo(const char **errcode_desc, const char **description, + const char **filename, int *line); + +/** Maps IPP error codes to the counterparts from OpenCV */ +CVAPI(int) cvErrorFromIppStatus(int ipp_status); + +typedef int(CV_CDECL *CvErrorCallback)(int status, const char *func_name, + const char *err_msg, + const char *file_name, int line, + void *userdata); + +/** Assigns a new error-handling function */ +CVAPI(CvErrorCallback) +cvRedirectError(CvErrorCallback error_handler, void *userdata CV_DEFAULT(NULL), + void **prev_userdata CV_DEFAULT(NULL)); + +/** Output nothing */ +CVAPI(int) +cvNulDevReport(int status, const char *func_name, const char *err_msg, + const char *file_name, int line, void *userdata); + +/** Output to console(fprintf(stderr,...)) */ +CVAPI(int) +cvStdErrReport(int status, const char *func_name, const char *err_msg, + const char *file_name, int line, void *userdata); + +/** Output to MessageBox(WIN32) */ +CVAPI(int) +cvGuiBoxReport(int status, const char *func_name, const char *err_msg, + const char *file_name, int line, void *userdata); + +#define OPENCV_ERROR(status, func, context) \ + cvError((status), (func), (context), __FILE__, __LINE__) + +#define OPENCV_ASSERT(expr, func, context) \ + { \ + if (!(expr)) { \ + OPENCV_ERROR(CV_StsInternal, (func), (context)); \ + } \ + } + +#define OPENCV_CALL(Func) \ + { \ + Func; \ + } + +/** CV_FUNCNAME macro defines icvFuncName constant which is used by CV_ERROR + * macro */ +#ifdef CV_NO_FUNC_NAMES +#define CV_FUNCNAME(Name) +#define cvFuncName "" +#else +#define CV_FUNCNAME(Name) static char cvFuncName[] = Name +#endif + +/** + CV_ERROR macro unconditionally raises error with passed code and message. + After raising error, control will be transferred to the exit label. + */ +#define CV_ERROR(Code, Msg) \ + { \ + cvError((Code), cvFuncName, Msg, __FILE__, __LINE__); \ + __CV_EXIT__; \ + } + +/** + CV_CHECK macro checks error status after CV (or IPL) + function call. If error detected, control will be transferred to the exit + label. + */ +#define CV_CHECK() \ + { \ + if (cvGetErrStatus() < 0) \ + CV_ERROR(CV_StsBackTrace, "Inner function failed."); \ + } + +/** + CV_CALL macro calls CV (or IPL) function, checks error status and + signals a error if the function failed. Useful in "parent node" + error processing mode + */ +#define CV_CALL(Func) \ + { \ + Func; \ + CV_CHECK(); \ + } + +/** Runtime assertion macro */ +#define CV_ASSERT(Condition) \ + { \ + if (!(Condition)) \ + CV_ERROR(CV_StsInternal, "Assertion: " #Condition " failed"); \ + } + +#define __CV_BEGIN__ { +#define __CV_END__ \ + goto exit; \ + exit:; \ + } +#define __CV_EXIT__ goto exit + +/** @} core_c */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus + +#include "opencv2/core/utility.hpp" + +namespace cv { + +//! @addtogroup core_c_glue +//! @{ + +/////////////////////////////////////////// glue +////////////////////////////////////////////// + +//! converts array (CvMat or IplImage) to cv::Mat +CV_EXPORTS Mat cvarrToMat(const CvArr *arr, bool copyData = false, + bool allowND = true, int coiMode = 0, + AutoBuffer *buf = 0); + +static inline Mat cvarrToMatND(const CvArr *arr, bool copyData = false, + int coiMode = 0) { + return cvarrToMat(arr, copyData, true, coiMode); +} + +//! extracts Channel of Interest from CvMat or IplImage and makes cv::Mat out of +//! it. +CV_EXPORTS void extractImageCOI(const CvArr *arr, OutputArray coiimg, + int coi = -1); +//! inserts single-channel cv::Mat into a multi-channel CvMat or IplImage +CV_EXPORTS void insertImageCOI(InputArray coiimg, CvArr *arr, int coi = -1); + +////// specialized implementations of DefaultDeleter::operator() for classic +/// OpenCV types ////// + +template <> struct DefaultDeleter { + CV_EXPORTS void operator()(CvMat *obj) const; +}; +template <> struct DefaultDeleter { + CV_EXPORTS void operator()(IplImage *obj) const; +}; +template <> struct DefaultDeleter { + CV_EXPORTS void operator()(CvMatND *obj) const; +}; +template <> struct DefaultDeleter { + CV_EXPORTS void operator()(CvSparseMat *obj) const; +}; +template <> struct DefaultDeleter { + CV_EXPORTS void operator()(CvMemStorage *obj) const; +}; + +////////////// convenient wrappers for operating old-style dynamic structures +///////////////// + +template class SeqIterator; + +typedef Ptr MemStorage; + +/*! + Template Sequence Class derived from CvSeq + + The class provides more convenient access to sequence elements, + STL-style operations and iterators. + + \note The class is targeted for simple data types, + i.e. no constructors or destructors + are called for the sequence elements. +*/ +template class Seq { +public: + typedef SeqIterator<_Tp> iterator; + typedef SeqIterator<_Tp> const_iterator; + + //! the default constructor + Seq(); + //! the constructor for wrapping CvSeq structure. The real element type in + //! CvSeq should match _Tp. + Seq(const CvSeq *seq); + //! creates the empty sequence that resides in the specified storage + Seq(MemStorage &storage, int headerSize = sizeof(CvSeq)); + //! returns read-write reference to the specified element + _Tp &operator[](int idx); + //! returns read-only reference to the specified element + const _Tp &operator[](int idx) const; + //! returns iterator pointing to the beginning of the sequence + SeqIterator<_Tp> begin() const; + //! returns iterator pointing to the element following the last sequence + //! element + SeqIterator<_Tp> end() const; + //! returns the number of elements in the sequence + size_t size() const; + //! returns the type of sequence elements (CV_8UC1 ... CV_64FC(CV_CN_MAX) ...) + int type() const; + //! returns the depth of sequence elements (CV_8U ... CV_64F) + int depth() const; + //! returns the number of channels in each sequence element + int channels() const; + //! returns the size of each sequence element + size_t elemSize() const; + //! returns index of the specified sequence element + size_t index(const _Tp &elem) const; + //! appends the specified element to the end of the sequence + void push_back(const _Tp &elem); + //! appends the specified element to the front of the sequence + void push_front(const _Tp &elem); + //! appends zero or more elements to the end of the sequence + void push_back(const _Tp *elems, size_t count); + //! appends zero or more elements to the front of the sequence + void push_front(const _Tp *elems, size_t count); + //! inserts the specified element to the specified position + void insert(int idx, const _Tp &elem); + //! inserts zero or more elements to the specified position + void insert(int idx, const _Tp *elems, size_t count); + //! removes element at the specified position + void remove(int idx); + //! removes the specified subsequence + void remove(const Range &r); + + //! returns reference to the first sequence element + _Tp &front(); + //! returns read-only reference to the first sequence element + const _Tp &front() const; + //! returns reference to the last sequence element + _Tp &back(); + //! returns read-only reference to the last sequence element + const _Tp &back() const; + //! returns true iff the sequence contains no elements + bool empty() const; + + //! removes all the elements from the sequence + void clear(); + //! removes the first element from the sequence + void pop_front(); + //! removes the last element from the sequence + void pop_back(); + //! removes zero or more elements from the beginning of the sequence + void pop_front(_Tp *elems, size_t count); + //! removes zero or more elements from the end of the sequence + void pop_back(_Tp *elems, size_t count); + + //! copies the whole sequence or the sequence slice to the specified vector + void copyTo(std::vector<_Tp> &vec, const Range &range = Range::all()) const; + //! returns the vector containing all the sequence elements + operator std::vector<_Tp>() const; + + CvSeq *seq; +}; + +/*! + STL-style Sequence Iterator inherited from the CvSeqReader structure +*/ +template class SeqIterator : public CvSeqReader { +public: + //! the default constructor + SeqIterator(); + //! the constructor setting the iterator to the beginning or to the end of the + //! sequence + SeqIterator(const Seq<_Tp> &seq, bool seekEnd = false); + //! positions the iterator within the sequence + void seek(size_t pos); + //! reports the current iterator position + size_t tell() const; + //! returns reference to the current sequence element + _Tp &operator*(); + //! returns read-only reference to the current sequence element + const _Tp &operator*() const; + //! moves iterator to the next sequence element + SeqIterator &operator++(); + //! moves iterator to the next sequence element + SeqIterator operator++(int) const; + //! moves iterator to the previous sequence element + SeqIterator &operator--(); + //! moves iterator to the previous sequence element + SeqIterator operator--(int) const; + + //! moves iterator forward by the specified offset (possibly negative) + SeqIterator &operator+=(int); + //! moves iterator backward by the specified offset (possibly negative) + SeqIterator &operator-=(int); + + // this is index of the current element module seq->total*2 + // (to distinguish between 0 and seq->total) + int index; +}; + +// bridge C++ => C Seq API +CV_EXPORTS schar *seqPush(CvSeq *seq, const void *element = 0); +CV_EXPORTS schar *seqPushFront(CvSeq *seq, const void *element = 0); +CV_EXPORTS void seqPop(CvSeq *seq, void *element = 0); +CV_EXPORTS void seqPopFront(CvSeq *seq, void *element = 0); +CV_EXPORTS void seqPopMulti(CvSeq *seq, void *elements, int count, + int in_front = 0); +CV_EXPORTS void seqRemove(CvSeq *seq, int index); +CV_EXPORTS void clearSeq(CvSeq *seq); +CV_EXPORTS schar *getSeqElem(const CvSeq *seq, int index); +CV_EXPORTS void seqRemoveSlice(CvSeq *seq, CvSlice slice); +CV_EXPORTS void seqInsertSlice(CvSeq *seq, int before_index, + const CvArr *from_arr); + +template inline Seq<_Tp>::Seq() : seq(0) {} +template +inline Seq<_Tp>::Seq(const CvSeq *_seq) : seq((CvSeq *)_seq) { + CV_Assert(!_seq || _seq->elem_size == sizeof(_Tp)); +} + +template +inline Seq<_Tp>::Seq(MemStorage &storage, int headerSize) { + CV_Assert(headerSize >= (int)sizeof(CvSeq)); + seq = cvCreateSeq(DataType<_Tp>::type, headerSize, sizeof(_Tp), storage); +} + +template inline _Tp &Seq<_Tp>::operator[](int idx) { + return *(_Tp *)getSeqElem(seq, idx); +} + +template inline const _Tp &Seq<_Tp>::operator[](int idx) const { + return *(_Tp *)getSeqElem(seq, idx); +} + +template inline SeqIterator<_Tp> Seq<_Tp>::begin() const { + return SeqIterator<_Tp>(*this); +} + +template inline SeqIterator<_Tp> Seq<_Tp>::end() const { + return SeqIterator<_Tp>(*this, true); +} + +template inline size_t Seq<_Tp>::size() const { + return seq ? seq->total : 0; +} + +template inline int Seq<_Tp>::type() const { + return seq ? CV_MAT_TYPE(seq->flags) : 0; +} + +template inline int Seq<_Tp>::depth() const { + return seq ? CV_MAT_DEPTH(seq->flags) : 0; +} + +template inline int Seq<_Tp>::channels() const { + return seq ? CV_MAT_CN(seq->flags) : 0; +} + +template inline size_t Seq<_Tp>::elemSize() const { + return seq ? seq->elem_size : 0; +} + +template inline size_t Seq<_Tp>::index(const _Tp &elem) const { + return cvSeqElemIdx(seq, &elem); +} + +template inline void Seq<_Tp>::push_back(const _Tp &elem) { + cvSeqPush(seq, &elem); +} + +template inline void Seq<_Tp>::push_front(const _Tp &elem) { + cvSeqPushFront(seq, &elem); +} + +template +inline void Seq<_Tp>::push_back(const _Tp *elem, size_t count) { + cvSeqPushMulti(seq, elem, (int)count, 0); +} + +template +inline void Seq<_Tp>::push_front(const _Tp *elem, size_t count) { + cvSeqPushMulti(seq, elem, (int)count, 1); +} + +template inline _Tp &Seq<_Tp>::back() { + return *(_Tp *)getSeqElem(seq, -1); +} + +template inline const _Tp &Seq<_Tp>::back() const { + return *(const _Tp *)getSeqElem(seq, -1); +} + +template inline _Tp &Seq<_Tp>::front() { + return *(_Tp *)getSeqElem(seq, 0); +} + +template inline const _Tp &Seq<_Tp>::front() const { + return *(const _Tp *)getSeqElem(seq, 0); +} + +template inline bool Seq<_Tp>::empty() const { + return !seq || seq->total == 0; +} + +template inline void Seq<_Tp>::clear() { + if (seq) + clearSeq(seq); +} + +template inline void Seq<_Tp>::pop_back() { seqPop(seq); } + +template inline void Seq<_Tp>::pop_front() { seqPopFront(seq); } + +template +inline void Seq<_Tp>::pop_back(_Tp *elem, size_t count) { + seqPopMulti(seq, elem, (int)count, 0); +} + +template +inline void Seq<_Tp>::pop_front(_Tp *elem, size_t count) { + seqPopMulti(seq, elem, (int)count, 1); +} + +template inline void Seq<_Tp>::insert(int idx, const _Tp &elem) { + seqInsert(seq, idx, &elem); +} + +template +inline void Seq<_Tp>::insert(int idx, const _Tp *elems, size_t count) { + CvMat m = cvMat(1, count, DataType<_Tp>::type, elems); + seqInsertSlice(seq, idx, &m); +} + +template inline void Seq<_Tp>::remove(int idx) { + seqRemove(seq, idx); +} + +template inline void Seq<_Tp>::remove(const Range &r) { + seqRemoveSlice(seq, cvSlice(r.start, r.end)); +} + +template +inline void Seq<_Tp>::copyTo(std::vector<_Tp> &vec, const Range &range) const { + size_t len = !seq ? 0 + : range == Range::all() ? seq->total + : range.end - range.start; + vec.resize(len); + if (seq && len) + cvCvtSeqToArray(seq, &vec[0], cvSlice(range)); +} + +template inline Seq<_Tp>::operator std::vector<_Tp>() const { + std::vector<_Tp> vec; + copyTo(vec); + return vec; +} + +template inline SeqIterator<_Tp>::SeqIterator() { + memset(this, 0, sizeof(*this)); +} + +template +inline SeqIterator<_Tp>::SeqIterator(const Seq<_Tp> &_seq, bool seekEnd) { + cvStartReadSeq(_seq.seq, this); + index = seekEnd ? _seq.seq->total : 0; +} + +template inline void SeqIterator<_Tp>::seek(size_t pos) { + cvSetSeqReaderPos(this, (int)pos, false); + index = pos; +} + +template inline size_t SeqIterator<_Tp>::tell() const { + return index; +} + +template inline _Tp &SeqIterator<_Tp>::operator*() { + return *(_Tp *)ptr; +} + +template inline const _Tp &SeqIterator<_Tp>::operator*() const { + return *(const _Tp *)ptr; +} + +template +inline SeqIterator<_Tp> &SeqIterator<_Tp>::operator++() { + CV_NEXT_SEQ_ELEM(sizeof(_Tp), *this); + if (++index >= seq->total * 2) + index = 0; + return *this; +} + +template +inline SeqIterator<_Tp> SeqIterator<_Tp>::operator++(int) const { + SeqIterator<_Tp> it = *this; + ++*this; + return it; +} + +template +inline SeqIterator<_Tp> &SeqIterator<_Tp>::operator--() { + CV_PREV_SEQ_ELEM(sizeof(_Tp), *this); + if (--index < 0) + index = seq->total * 2 - 1; + return *this; +} + +template +inline SeqIterator<_Tp> SeqIterator<_Tp>::operator--(int) const { + SeqIterator<_Tp> it = *this; + --*this; + return it; +} + +template +inline SeqIterator<_Tp> &SeqIterator<_Tp>::operator+=(int delta) { + cvSetSeqReaderPos(this, delta, 1); + index += delta; + int n = seq->total * 2; + if (index < 0) + index += n; + if (index >= n) + index -= n; + return *this; +} + +template +inline SeqIterator<_Tp> &SeqIterator<_Tp>::operator-=(int delta) { + return (*this += -delta); +} + +template +inline ptrdiff_t operator-(const SeqIterator<_Tp> &a, + const SeqIterator<_Tp> &b) { + ptrdiff_t delta = a.index - b.index, n = a.seq->total; + if (delta > n || delta < -n) + delta += delta < 0 ? n : -n; + return delta; +} + +template +inline bool operator==(const SeqIterator<_Tp> &a, const SeqIterator<_Tp> &b) { + return a.seq == b.seq && a.index == b.index; +} + +template +inline bool operator!=(const SeqIterator<_Tp> &a, const SeqIterator<_Tp> &b) { + return !(a == b); +} + +//! @} + +} // namespace cv + +#endif + +#endif diff --git a/third-party/include/opencv2/core/cv_cpu_dispatch.h b/third-party/include/opencv2/core/cv_cpu_dispatch.h new file mode 100644 index 0000000000..8a0c1b3935 --- /dev/null +++ b/third-party/include/opencv2/core/cv_cpu_dispatch.h @@ -0,0 +1,404 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. + +#if defined __OPENCV_BUILD + +#include "cv_cpu_config.h" +#include "cv_cpu_helper.h" + +#ifdef CV_CPU_DISPATCH_MODE +#define CV_CPU_OPTIMIZATION_NAMESPACE __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN \ + namespace __CV_CAT(opt_, CV_CPU_DISPATCH_MODE) { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } +#else +#define CV_CPU_OPTIMIZATION_NAMESPACE cpu_baseline +#define CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN namespace cpu_baseline { +#define CV_CPU_OPTIMIZATION_NAMESPACE_END } +#define CV_CPU_BASELINE_MODE 1 +#endif + +#define __CV_CPU_DISPATCH_CHAIN_END(fn, args, mode, ...) /* done */ +#define __CV_CPU_DISPATCH(fn, args, mode, ...) \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) +#define __CV_CPU_DISPATCH_EXPAND(fn, args, ...) \ + __CV_EXPAND(__CV_CPU_DISPATCH(fn, args, __VA_ARGS__)) +#define CV_CPU_DISPATCH(fn, args, ...) \ + __CV_CPU_DISPATCH_EXPAND(fn, args, __VA_ARGS__, END) // expand macros + +#if defined CV_ENABLE_INTRINSICS && !defined CV_DISABLE_OPTIMIZATION && \ + !defined __CUDACC__ /* do not include SSE/AVX/NEON headers for NVCC \ + compiler */ + +#ifdef CV_CPU_COMPILE_SSE2 +#include +#define CV_MMX 1 +#define CV_SSE 1 +#define CV_SSE2 1 +#endif +#ifdef CV_CPU_COMPILE_SSE3 +#include +#define CV_SSE3 1 +#endif +#ifdef CV_CPU_COMPILE_SSSE3 +#include +#define CV_SSSE3 1 +#endif +#ifdef CV_CPU_COMPILE_SSE4_1 +#include +#define CV_SSE4_1 1 +#endif +#ifdef CV_CPU_COMPILE_SSE4_2 +#include +#define CV_SSE4_2 1 +#endif +#ifdef CV_CPU_COMPILE_POPCNT +#ifdef _MSC_VER +#include +#if defined(_M_X64) +#define CV_POPCNT_U64 (int)_mm_popcnt_u64 +#endif +#define CV_POPCNT_U32 _mm_popcnt_u32 +#else +#include +#if defined(__x86_64__) +#define CV_POPCNT_U64 __builtin_popcountll +#endif +#define CV_POPCNT_U32 __builtin_popcount +#endif +#define CV_POPCNT 1 +#endif +#ifdef CV_CPU_COMPILE_AVX +#include +#define CV_AVX 1 +#endif +#ifdef CV_CPU_COMPILE_FP16 +#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || \ + defined(_M_ARM64) +#include +#else +#include +#endif +#define CV_FP16 1 +#endif +#ifdef CV_CPU_COMPILE_NEON_DOTPROD +#include +#define CV_NEON_DOT 1 +#endif +#ifdef CV_CPU_COMPILE_AVX2 +#include +#define CV_AVX2 1 +#endif +#ifdef CV_CPU_COMPILE_AVX_512F +#include +#define CV_AVX_512F 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_COMMON +#define CV_AVX512_COMMON 1 +#define CV_AVX_512CD 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_KNL +#define CV_AVX512_KNL 1 +#define CV_AVX_512ER 1 +#define CV_AVX_512PF 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_KNM +#define CV_AVX512_KNM 1 +#define CV_AVX_5124FMAPS 1 +#define CV_AVX_5124VNNIW 1 +#define CV_AVX_512VPOPCNTDQ 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_SKX +#define CV_AVX512_SKX 1 +#define CV_AVX_512VL 1 +#define CV_AVX_512BW 1 +#define CV_AVX_512DQ 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_CNL +#define CV_AVX512_CNL 1 +#define CV_AVX_512IFMA 1 +#define CV_AVX_512VBMI 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_CLX +#define CV_AVX512_CLX 1 +#define CV_AVX_512VNNI 1 +#endif +#ifdef CV_CPU_COMPILE_AVX512_ICL +#define CV_AVX512_ICL 1 +#undef CV_AVX_512IFMA +#define CV_AVX_512IFMA 1 +#undef CV_AVX_512VBMI +#define CV_AVX_512VBMI 1 +#undef CV_AVX_512VNNI +#define CV_AVX_512VNNI 1 +#define CV_AVX_512VBMI2 1 +#define CV_AVX_512BITALG 1 +#define CV_AVX_512VPOPCNTDQ 1 +#endif +#ifdef CV_CPU_COMPILE_FMA3 +#define CV_FMA3 1 +#endif + +#if defined _WIN32 && (defined(_M_ARM) || defined(_M_ARM64)) && \ + (defined(CV_CPU_COMPILE_NEON) || !defined(_MSC_VER)) +#include +#include +#define CV_NEON 1 +#elif defined(__ARM_NEON) +#include +#define CV_NEON 1 +#endif + +/* RVV-related macro states with different compiler +// +--------------------+----------+----------+ +// | Macro | Upstream | XuanTie | +// +--------------------+----------+----------+ +// | CV_CPU_COMPILE_RVV | defined | defined | +// | CV_RVV | 1 | 0 | +// | CV_RVV071 | 0 | 1 | +// | CV_TRY_RVV | 1 | 1 | +// +--------------------+----------+----------+ +*/ +#ifdef CV_CPU_COMPILE_RVV +#ifdef __riscv_vector_071 +#define CV_RVV071 1 +#else +#define CV_RVV 1 +#endif +#include +#endif + +#ifdef CV_CPU_COMPILE_VSX +#include +#undef vector +#undef pixel +#undef bool +#define CV_VSX 1 +#endif + +#ifdef CV_CPU_COMPILE_VSX3 +#define CV_VSX3 1 +#endif + +#ifdef CV_CPU_COMPILE_MSA +#include "hal/msa_macros.h" +#define CV_MSA 1 +#endif + +#ifdef CV_CPU_COMPILE_LSX +#include +#define CV_LSX 1 +#endif + +#ifdef CV_CPU_COMPILE_LASX +#include +#define CV_LASX 1 +#endif + +#ifdef __EMSCRIPTEN__ +#define CV_WASM_SIMD 1 +#include +#endif + +#endif // CV_ENABLE_INTRINSICS && !CV_DISABLE_OPTIMIZATION && !__CUDACC__ + +#if defined CV_CPU_COMPILE_AVX && !defined CV_CPU_BASELINE_COMPILE_AVX +struct VZeroUpperGuard { +#ifdef __GNUC__ + __attribute__((always_inline)) +#endif + inline VZeroUpperGuard() { + _mm256_zeroupper(); + } +#ifdef __GNUC__ + __attribute__((always_inline)) +#endif + inline ~VZeroUpperGuard() { + _mm256_zeroupper(); + } +}; +#define __CV_AVX_GUARD \ + VZeroUpperGuard __vzeroupper_guard; \ + CV_UNUSED(__vzeroupper_guard); +#endif + +#ifdef __CV_AVX_GUARD +#define CV_AVX_GUARD __CV_AVX_GUARD +#else +#define CV_AVX_GUARD +#endif + +#endif // __OPENCV_BUILD + +#if !defined __OPENCV_BUILD /* Compatibility code */ \ + && !defined __CUDACC__ /* do not include SSE/AVX/NEON headers for NVCC \ + compiler */ +#if defined __SSE2__ || defined _M_X64 || \ + (defined _M_IX86_FP && _M_IX86_FP >= 2) +#include +#define CV_MMX 1 +#define CV_SSE 1 +#define CV_SSE2 1 +#elif defined _WIN32 && (defined(_M_ARM) || defined(_M_ARM64)) && \ + (defined(CV_CPU_COMPILE_NEON) || !defined(_MSC_VER)) +#include +#include +#define CV_NEON 1 +#elif defined(__ARM_NEON) +#include +#define CV_NEON 1 +#elif defined(__VSX__) && defined(__PPC64__) && defined(__LITTLE_ENDIAN__) +#include +#undef vector +#undef pixel +#undef bool +#define CV_VSX 1 +#endif + +#ifdef __F16C__ +#include +#define CV_FP16 1 +#endif + +#endif // !__OPENCV_BUILD && !__CUDACC (Compatibility code) + +#ifndef CV_MMX +#define CV_MMX 0 +#endif +#ifndef CV_SSE +#define CV_SSE 0 +#endif +#ifndef CV_SSE2 +#define CV_SSE2 0 +#endif +#ifndef CV_SSE3 +#define CV_SSE3 0 +#endif +#ifndef CV_SSSE3 +#define CV_SSSE3 0 +#endif +#ifndef CV_SSE4_1 +#define CV_SSE4_1 0 +#endif +#ifndef CV_SSE4_2 +#define CV_SSE4_2 0 +#endif +#ifndef CV_POPCNT +#define CV_POPCNT 0 +#endif +#ifndef CV_AVX +#define CV_AVX 0 +#endif +#ifndef CV_FP16 +#define CV_FP16 0 +#endif +#ifndef CV_AVX2 +#define CV_AVX2 0 +#endif +#ifndef CV_FMA3 +#define CV_FMA3 0 +#endif +#ifndef CV_AVX_512F +#define CV_AVX_512F 0 +#endif +#ifndef CV_AVX_512BW +#define CV_AVX_512BW 0 +#endif +#ifndef CV_AVX_512CD +#define CV_AVX_512CD 0 +#endif +#ifndef CV_AVX_512DQ +#define CV_AVX_512DQ 0 +#endif +#ifndef CV_AVX_512ER +#define CV_AVX_512ER 0 +#endif +#ifndef CV_AVX_512IFMA +#define CV_AVX_512IFMA 0 +#endif +#define CV_AVX_512IFMA512 CV_AVX_512IFMA // deprecated +#ifndef CV_AVX_512PF +#define CV_AVX_512PF 0 +#endif +#ifndef CV_AVX_512VBMI +#define CV_AVX_512VBMI 0 +#endif +#ifndef CV_AVX_512VL +#define CV_AVX_512VL 0 +#endif +#ifndef CV_AVX_5124FMAPS +#define CV_AVX_5124FMAPS 0 +#endif +#ifndef CV_AVX_5124VNNIW +#define CV_AVX_5124VNNIW 0 +#endif +#ifndef CV_AVX_512VPOPCNTDQ +#define CV_AVX_512VPOPCNTDQ 0 +#endif +#ifndef CV_AVX_512VNNI +#define CV_AVX_512VNNI 0 +#endif +#ifndef CV_AVX_512VBMI2 +#define CV_AVX_512VBMI2 0 +#endif +#ifndef CV_AVX_512BITALG +#define CV_AVX_512BITALG 0 +#endif +#ifndef CV_AVX512_COMMON +#define CV_AVX512_COMMON 0 +#endif +#ifndef CV_AVX512_KNL +#define CV_AVX512_KNL 0 +#endif +#ifndef CV_AVX512_KNM +#define CV_AVX512_KNM 0 +#endif +#ifndef CV_AVX512_SKX +#define CV_AVX512_SKX 0 +#endif +#ifndef CV_AVX512_CNL +#define CV_AVX512_CNL 0 +#endif +#ifndef CV_AVX512_CLX +#define CV_AVX512_CLX 0 +#endif +#ifndef CV_AVX512_ICL +#define CV_AVX512_ICL 0 +#endif + +#ifndef CV_NEON +#define CV_NEON 0 +#endif + +#ifndef CV_RVV071 +#define CV_RVV071 0 +#endif + +#ifndef CV_VSX +#define CV_VSX 0 +#endif + +#ifndef CV_VSX3 +#define CV_VSX3 0 +#endif + +#ifndef CV_MSA +#define CV_MSA 0 +#endif + +#ifndef CV_WASM_SIMD +#define CV_WASM_SIMD 0 +#endif + +#ifndef CV_RVV +#define CV_RVV 0 +#endif + +#ifndef CV_LSX +#define CV_LSX 0 +#endif + +#ifndef CV_LASX +#define CV_LASX 0 +#endif diff --git a/third-party/include/opencv2/core/cv_cpu_helper.h b/third-party/include/opencv2/core/cv_cpu_helper.h new file mode 100644 index 0000000000..088eb47c0d --- /dev/null +++ b/third-party/include/opencv2/core/cv_cpu_helper.h @@ -0,0 +1,856 @@ +// AUTOGENERATED, DO NOT EDIT + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_SSE +#define CV_TRY_SSE 1 +#define CV_CPU_FORCE_SSE 1 +#define CV_CPU_HAS_SUPPORT_SSE 1 +#define CV_CPU_CALL_SSE(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_SSE_(fn, args) return (opt_SSE::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_SSE +#define CV_TRY_SSE 1 +#define CV_CPU_FORCE_SSE 0 +#define CV_CPU_HAS_SUPPORT_SSE (cv::checkHardwareSupport(CV_CPU_SSE)) +#define CV_CPU_CALL_SSE(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE) \ + return (opt_SSE::fn args) +#define CV_CPU_CALL_SSE_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE) \ + return (opt_SSE::fn args) +#else +#define CV_TRY_SSE 0 +#define CV_CPU_FORCE_SSE 0 +#define CV_CPU_HAS_SUPPORT_SSE 0 +#define CV_CPU_CALL_SSE(fn, args) +#define CV_CPU_CALL_SSE_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE(fn, args, mode, ...) \ + CV_CPU_CALL_SSE(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_SSE2 +#define CV_TRY_SSE2 1 +#define CV_CPU_FORCE_SSE2 1 +#define CV_CPU_HAS_SUPPORT_SSE2 1 +#define CV_CPU_CALL_SSE2(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_SSE2_(fn, args) return (opt_SSE2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_SSE2 +#define CV_TRY_SSE2 1 +#define CV_CPU_FORCE_SSE2 0 +#define CV_CPU_HAS_SUPPORT_SSE2 (cv::checkHardwareSupport(CV_CPU_SSE2)) +#define CV_CPU_CALL_SSE2(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE2) \ + return (opt_SSE2::fn args) +#define CV_CPU_CALL_SSE2_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE2) \ + return (opt_SSE2::fn args) +#else +#define CV_TRY_SSE2 0 +#define CV_CPU_FORCE_SSE2 0 +#define CV_CPU_HAS_SUPPORT_SSE2 0 +#define CV_CPU_CALL_SSE2(fn, args) +#define CV_CPU_CALL_SSE2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE2(fn, args, mode, ...) \ + CV_CPU_CALL_SSE2(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_SSE3 +#define CV_TRY_SSE3 1 +#define CV_CPU_FORCE_SSE3 1 +#define CV_CPU_HAS_SUPPORT_SSE3 1 +#define CV_CPU_CALL_SSE3(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_SSE3_(fn, args) return (opt_SSE3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_SSE3 +#define CV_TRY_SSE3 1 +#define CV_CPU_FORCE_SSE3 0 +#define CV_CPU_HAS_SUPPORT_SSE3 (cv::checkHardwareSupport(CV_CPU_SSE3)) +#define CV_CPU_CALL_SSE3(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE3) \ + return (opt_SSE3::fn args) +#define CV_CPU_CALL_SSE3_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE3) \ + return (opt_SSE3::fn args) +#else +#define CV_TRY_SSE3 0 +#define CV_CPU_FORCE_SSE3 0 +#define CV_CPU_HAS_SUPPORT_SSE3 0 +#define CV_CPU_CALL_SSE3(fn, args) +#define CV_CPU_CALL_SSE3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE3(fn, args, mode, ...) \ + CV_CPU_CALL_SSE3(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_SSSE3 +#define CV_TRY_SSSE3 1 +#define CV_CPU_FORCE_SSSE3 1 +#define CV_CPU_HAS_SUPPORT_SSSE3 1 +#define CV_CPU_CALL_SSSE3(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_SSSE3_(fn, args) return (opt_SSSE3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_SSSE3 +#define CV_TRY_SSSE3 1 +#define CV_CPU_FORCE_SSSE3 0 +#define CV_CPU_HAS_SUPPORT_SSSE3 (cv::checkHardwareSupport(CV_CPU_SSSE3)) +#define CV_CPU_CALL_SSSE3(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSSE3) \ + return (opt_SSSE3::fn args) +#define CV_CPU_CALL_SSSE3_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSSE3) \ + return (opt_SSSE3::fn args) +#else +#define CV_TRY_SSSE3 0 +#define CV_CPU_FORCE_SSSE3 0 +#define CV_CPU_HAS_SUPPORT_SSSE3 0 +#define CV_CPU_CALL_SSSE3(fn, args) +#define CV_CPU_CALL_SSSE3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSSE3(fn, args, mode, ...) \ + CV_CPU_CALL_SSSE3(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_SSE4_1 +#define CV_TRY_SSE4_1 1 +#define CV_CPU_FORCE_SSE4_1 1 +#define CV_CPU_HAS_SUPPORT_SSE4_1 1 +#define CV_CPU_CALL_SSE4_1(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_SSE4_1_(fn, args) return (opt_SSE4_1::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_SSE4_1 +#define CV_TRY_SSE4_1 1 +#define CV_CPU_FORCE_SSE4_1 0 +#define CV_CPU_HAS_SUPPORT_SSE4_1 (cv::checkHardwareSupport(CV_CPU_SSE4_1)) +#define CV_CPU_CALL_SSE4_1(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE4_1) \ + return (opt_SSE4_1::fn args) +#define CV_CPU_CALL_SSE4_1_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE4_1) \ + return (opt_SSE4_1::fn args) +#else +#define CV_TRY_SSE4_1 0 +#define CV_CPU_FORCE_SSE4_1 0 +#define CV_CPU_HAS_SUPPORT_SSE4_1 0 +#define CV_CPU_CALL_SSE4_1(fn, args) +#define CV_CPU_CALL_SSE4_1_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE4_1(fn, args, mode, ...) \ + CV_CPU_CALL_SSE4_1(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_SSE4_2 +#define CV_TRY_SSE4_2 1 +#define CV_CPU_FORCE_SSE4_2 1 +#define CV_CPU_HAS_SUPPORT_SSE4_2 1 +#define CV_CPU_CALL_SSE4_2(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_SSE4_2_(fn, args) return (opt_SSE4_2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_SSE4_2 +#define CV_TRY_SSE4_2 1 +#define CV_CPU_FORCE_SSE4_2 0 +#define CV_CPU_HAS_SUPPORT_SSE4_2 (cv::checkHardwareSupport(CV_CPU_SSE4_2)) +#define CV_CPU_CALL_SSE4_2(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE4_2) \ + return (opt_SSE4_2::fn args) +#define CV_CPU_CALL_SSE4_2_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_SSE4_2) \ + return (opt_SSE4_2::fn args) +#else +#define CV_TRY_SSE4_2 0 +#define CV_CPU_FORCE_SSE4_2 0 +#define CV_CPU_HAS_SUPPORT_SSE4_2 0 +#define CV_CPU_CALL_SSE4_2(fn, args) +#define CV_CPU_CALL_SSE4_2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_SSE4_2(fn, args, mode, ...) \ + CV_CPU_CALL_SSE4_2(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_POPCNT +#define CV_TRY_POPCNT 1 +#define CV_CPU_FORCE_POPCNT 1 +#define CV_CPU_HAS_SUPPORT_POPCNT 1 +#define CV_CPU_CALL_POPCNT(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_POPCNT_(fn, args) return (opt_POPCNT::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_POPCNT +#define CV_TRY_POPCNT 1 +#define CV_CPU_FORCE_POPCNT 0 +#define CV_CPU_HAS_SUPPORT_POPCNT (cv::checkHardwareSupport(CV_CPU_POPCNT)) +#define CV_CPU_CALL_POPCNT(fn, args) \ + if (CV_CPU_HAS_SUPPORT_POPCNT) \ + return (opt_POPCNT::fn args) +#define CV_CPU_CALL_POPCNT_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_POPCNT) \ + return (opt_POPCNT::fn args) +#else +#define CV_TRY_POPCNT 0 +#define CV_CPU_FORCE_POPCNT 0 +#define CV_CPU_HAS_SUPPORT_POPCNT 0 +#define CV_CPU_CALL_POPCNT(fn, args) +#define CV_CPU_CALL_POPCNT_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_POPCNT(fn, args, mode, ...) \ + CV_CPU_CALL_POPCNT(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX +#define CV_TRY_AVX 1 +#define CV_CPU_FORCE_AVX 1 +#define CV_CPU_HAS_SUPPORT_AVX 1 +#define CV_CPU_CALL_AVX(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX_(fn, args) return (opt_AVX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX +#define CV_TRY_AVX 1 +#define CV_CPU_FORCE_AVX 0 +#define CV_CPU_HAS_SUPPORT_AVX (cv::checkHardwareSupport(CV_CPU_AVX)) +#define CV_CPU_CALL_AVX(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX) \ + return (opt_AVX::fn args) +#define CV_CPU_CALL_AVX_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX) \ + return (opt_AVX::fn args) +#else +#define CV_TRY_AVX 0 +#define CV_CPU_FORCE_AVX 0 +#define CV_CPU_HAS_SUPPORT_AVX 0 +#define CV_CPU_CALL_AVX(fn, args) +#define CV_CPU_CALL_AVX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX(fn, args, mode, ...) \ + CV_CPU_CALL_AVX(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_FP16 +#define CV_TRY_FP16 1 +#define CV_CPU_FORCE_FP16 1 +#define CV_CPU_HAS_SUPPORT_FP16 1 +#define CV_CPU_CALL_FP16(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_FP16_(fn, args) return (opt_FP16::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_FP16 +#define CV_TRY_FP16 1 +#define CV_CPU_FORCE_FP16 0 +#define CV_CPU_HAS_SUPPORT_FP16 (cv::checkHardwareSupport(CV_CPU_FP16)) +#define CV_CPU_CALL_FP16(fn, args) \ + if (CV_CPU_HAS_SUPPORT_FP16) \ + return (opt_FP16::fn args) +#define CV_CPU_CALL_FP16_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_FP16) \ + return (opt_FP16::fn args) +#else +#define CV_TRY_FP16 0 +#define CV_CPU_FORCE_FP16 0 +#define CV_CPU_HAS_SUPPORT_FP16 0 +#define CV_CPU_CALL_FP16(fn, args) +#define CV_CPU_CALL_FP16_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_FP16(fn, args, mode, ...) \ + CV_CPU_CALL_FP16(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX2 +#define CV_TRY_AVX2 1 +#define CV_CPU_FORCE_AVX2 1 +#define CV_CPU_HAS_SUPPORT_AVX2 1 +#define CV_CPU_CALL_AVX2(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX2_(fn, args) return (opt_AVX2::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX2 +#define CV_TRY_AVX2 1 +#define CV_CPU_FORCE_AVX2 0 +#define CV_CPU_HAS_SUPPORT_AVX2 (cv::checkHardwareSupport(CV_CPU_AVX2)) +#define CV_CPU_CALL_AVX2(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX2) \ + return (opt_AVX2::fn args) +#define CV_CPU_CALL_AVX2_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX2) \ + return (opt_AVX2::fn args) +#else +#define CV_TRY_AVX2 0 +#define CV_CPU_FORCE_AVX2 0 +#define CV_CPU_HAS_SUPPORT_AVX2 0 +#define CV_CPU_CALL_AVX2(fn, args) +#define CV_CPU_CALL_AVX2_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX2(fn, args, mode, ...) \ + CV_CPU_CALL_AVX2(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_FMA3 +#define CV_TRY_FMA3 1 +#define CV_CPU_FORCE_FMA3 1 +#define CV_CPU_HAS_SUPPORT_FMA3 1 +#define CV_CPU_CALL_FMA3(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_FMA3_(fn, args) return (opt_FMA3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_FMA3 +#define CV_TRY_FMA3 1 +#define CV_CPU_FORCE_FMA3 0 +#define CV_CPU_HAS_SUPPORT_FMA3 (cv::checkHardwareSupport(CV_CPU_FMA3)) +#define CV_CPU_CALL_FMA3(fn, args) \ + if (CV_CPU_HAS_SUPPORT_FMA3) \ + return (opt_FMA3::fn args) +#define CV_CPU_CALL_FMA3_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_FMA3) \ + return (opt_FMA3::fn args) +#else +#define CV_TRY_FMA3 0 +#define CV_CPU_FORCE_FMA3 0 +#define CV_CPU_HAS_SUPPORT_FMA3 0 +#define CV_CPU_CALL_FMA3(fn, args) +#define CV_CPU_CALL_FMA3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_FMA3(fn, args, mode, ...) \ + CV_CPU_CALL_FMA3(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX_512F +#define CV_TRY_AVX_512F 1 +#define CV_CPU_FORCE_AVX_512F 1 +#define CV_CPU_HAS_SUPPORT_AVX_512F 1 +#define CV_CPU_CALL_AVX_512F(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX_512F_(fn, args) return (opt_AVX_512F::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX_512F +#define CV_TRY_AVX_512F 1 +#define CV_CPU_FORCE_AVX_512F 0 +#define CV_CPU_HAS_SUPPORT_AVX_512F (cv::checkHardwareSupport(CV_CPU_AVX_512F)) +#define CV_CPU_CALL_AVX_512F(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX_512F) \ + return (opt_AVX_512F::fn args) +#define CV_CPU_CALL_AVX_512F_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX_512F) \ + return (opt_AVX_512F::fn args) +#else +#define CV_TRY_AVX_512F 0 +#define CV_CPU_FORCE_AVX_512F 0 +#define CV_CPU_HAS_SUPPORT_AVX_512F 0 +#define CV_CPU_CALL_AVX_512F(fn, args) +#define CV_CPU_CALL_AVX_512F_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX_512F(fn, args, mode, ...) \ + CV_CPU_CALL_AVX_512F(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX512_COMMON +#define CV_TRY_AVX512_COMMON 1 +#define CV_CPU_FORCE_AVX512_COMMON 1 +#define CV_CPU_HAS_SUPPORT_AVX512_COMMON 1 +#define CV_CPU_CALL_AVX512_COMMON(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX512_COMMON_(fn, args) return (opt_AVX512_COMMON::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX512_COMMON +#define CV_TRY_AVX512_COMMON 1 +#define CV_CPU_FORCE_AVX512_COMMON 0 +#define CV_CPU_HAS_SUPPORT_AVX512_COMMON \ + (cv::checkHardwareSupport(CV_CPU_AVX512_COMMON)) +#define CV_CPU_CALL_AVX512_COMMON(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_COMMON) \ + return (opt_AVX512_COMMON::fn args) +#define CV_CPU_CALL_AVX512_COMMON_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_COMMON) \ + return (opt_AVX512_COMMON::fn args) +#else +#define CV_TRY_AVX512_COMMON 0 +#define CV_CPU_FORCE_AVX512_COMMON 0 +#define CV_CPU_HAS_SUPPORT_AVX512_COMMON 0 +#define CV_CPU_CALL_AVX512_COMMON(fn, args) +#define CV_CPU_CALL_AVX512_COMMON_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_COMMON(fn, args, mode, ...) \ + CV_CPU_CALL_AVX512_COMMON(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX512_KNL +#define CV_TRY_AVX512_KNL 1 +#define CV_CPU_FORCE_AVX512_KNL 1 +#define CV_CPU_HAS_SUPPORT_AVX512_KNL 1 +#define CV_CPU_CALL_AVX512_KNL(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX512_KNL_(fn, args) return (opt_AVX512_KNL::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX512_KNL +#define CV_TRY_AVX512_KNL 1 +#define CV_CPU_FORCE_AVX512_KNL 0 +#define CV_CPU_HAS_SUPPORT_AVX512_KNL \ + (cv::checkHardwareSupport(CV_CPU_AVX512_KNL)) +#define CV_CPU_CALL_AVX512_KNL(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_KNL) \ + return (opt_AVX512_KNL::fn args) +#define CV_CPU_CALL_AVX512_KNL_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_KNL) \ + return (opt_AVX512_KNL::fn args) +#else +#define CV_TRY_AVX512_KNL 0 +#define CV_CPU_FORCE_AVX512_KNL 0 +#define CV_CPU_HAS_SUPPORT_AVX512_KNL 0 +#define CV_CPU_CALL_AVX512_KNL(fn, args) +#define CV_CPU_CALL_AVX512_KNL_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_KNL(fn, args, mode, ...) \ + CV_CPU_CALL_AVX512_KNL(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX512_KNM +#define CV_TRY_AVX512_KNM 1 +#define CV_CPU_FORCE_AVX512_KNM 1 +#define CV_CPU_HAS_SUPPORT_AVX512_KNM 1 +#define CV_CPU_CALL_AVX512_KNM(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX512_KNM_(fn, args) return (opt_AVX512_KNM::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX512_KNM +#define CV_TRY_AVX512_KNM 1 +#define CV_CPU_FORCE_AVX512_KNM 0 +#define CV_CPU_HAS_SUPPORT_AVX512_KNM \ + (cv::checkHardwareSupport(CV_CPU_AVX512_KNM)) +#define CV_CPU_CALL_AVX512_KNM(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_KNM) \ + return (opt_AVX512_KNM::fn args) +#define CV_CPU_CALL_AVX512_KNM_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_KNM) \ + return (opt_AVX512_KNM::fn args) +#else +#define CV_TRY_AVX512_KNM 0 +#define CV_CPU_FORCE_AVX512_KNM 0 +#define CV_CPU_HAS_SUPPORT_AVX512_KNM 0 +#define CV_CPU_CALL_AVX512_KNM(fn, args) +#define CV_CPU_CALL_AVX512_KNM_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_KNM(fn, args, mode, ...) \ + CV_CPU_CALL_AVX512_KNM(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX512_SKX +#define CV_TRY_AVX512_SKX 1 +#define CV_CPU_FORCE_AVX512_SKX 1 +#define CV_CPU_HAS_SUPPORT_AVX512_SKX 1 +#define CV_CPU_CALL_AVX512_SKX(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX512_SKX_(fn, args) return (opt_AVX512_SKX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX512_SKX +#define CV_TRY_AVX512_SKX 1 +#define CV_CPU_FORCE_AVX512_SKX 0 +#define CV_CPU_HAS_SUPPORT_AVX512_SKX \ + (cv::checkHardwareSupport(CV_CPU_AVX512_SKX)) +#define CV_CPU_CALL_AVX512_SKX(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_SKX) \ + return (opt_AVX512_SKX::fn args) +#define CV_CPU_CALL_AVX512_SKX_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_SKX) \ + return (opt_AVX512_SKX::fn args) +#else +#define CV_TRY_AVX512_SKX 0 +#define CV_CPU_FORCE_AVX512_SKX 0 +#define CV_CPU_HAS_SUPPORT_AVX512_SKX 0 +#define CV_CPU_CALL_AVX512_SKX(fn, args) +#define CV_CPU_CALL_AVX512_SKX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_SKX(fn, args, mode, ...) \ + CV_CPU_CALL_AVX512_SKX(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX512_CNL +#define CV_TRY_AVX512_CNL 1 +#define CV_CPU_FORCE_AVX512_CNL 1 +#define CV_CPU_HAS_SUPPORT_AVX512_CNL 1 +#define CV_CPU_CALL_AVX512_CNL(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX512_CNL_(fn, args) return (opt_AVX512_CNL::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX512_CNL +#define CV_TRY_AVX512_CNL 1 +#define CV_CPU_FORCE_AVX512_CNL 0 +#define CV_CPU_HAS_SUPPORT_AVX512_CNL \ + (cv::checkHardwareSupport(CV_CPU_AVX512_CNL)) +#define CV_CPU_CALL_AVX512_CNL(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_CNL) \ + return (opt_AVX512_CNL::fn args) +#define CV_CPU_CALL_AVX512_CNL_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_CNL) \ + return (opt_AVX512_CNL::fn args) +#else +#define CV_TRY_AVX512_CNL 0 +#define CV_CPU_FORCE_AVX512_CNL 0 +#define CV_CPU_HAS_SUPPORT_AVX512_CNL 0 +#define CV_CPU_CALL_AVX512_CNL(fn, args) +#define CV_CPU_CALL_AVX512_CNL_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_CNL(fn, args, mode, ...) \ + CV_CPU_CALL_AVX512_CNL(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX512_CLX +#define CV_TRY_AVX512_CLX 1 +#define CV_CPU_FORCE_AVX512_CLX 1 +#define CV_CPU_HAS_SUPPORT_AVX512_CLX 1 +#define CV_CPU_CALL_AVX512_CLX(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX512_CLX_(fn, args) return (opt_AVX512_CLX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX512_CLX +#define CV_TRY_AVX512_CLX 1 +#define CV_CPU_FORCE_AVX512_CLX 0 +#define CV_CPU_HAS_SUPPORT_AVX512_CLX \ + (cv::checkHardwareSupport(CV_CPU_AVX512_CLX)) +#define CV_CPU_CALL_AVX512_CLX(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_CLX) \ + return (opt_AVX512_CLX::fn args) +#define CV_CPU_CALL_AVX512_CLX_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_CLX) \ + return (opt_AVX512_CLX::fn args) +#else +#define CV_TRY_AVX512_CLX 0 +#define CV_CPU_FORCE_AVX512_CLX 0 +#define CV_CPU_HAS_SUPPORT_AVX512_CLX 0 +#define CV_CPU_CALL_AVX512_CLX(fn, args) +#define CV_CPU_CALL_AVX512_CLX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_CLX(fn, args, mode, ...) \ + CV_CPU_CALL_AVX512_CLX(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_AVX512_ICL +#define CV_TRY_AVX512_ICL 1 +#define CV_CPU_FORCE_AVX512_ICL 1 +#define CV_CPU_HAS_SUPPORT_AVX512_ICL 1 +#define CV_CPU_CALL_AVX512_ICL(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_AVX512_ICL_(fn, args) return (opt_AVX512_ICL::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_AVX512_ICL +#define CV_TRY_AVX512_ICL 1 +#define CV_CPU_FORCE_AVX512_ICL 0 +#define CV_CPU_HAS_SUPPORT_AVX512_ICL \ + (cv::checkHardwareSupport(CV_CPU_AVX512_ICL)) +#define CV_CPU_CALL_AVX512_ICL(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_ICL) \ + return (opt_AVX512_ICL::fn args) +#define CV_CPU_CALL_AVX512_ICL_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_AVX512_ICL) \ + return (opt_AVX512_ICL::fn args) +#else +#define CV_TRY_AVX512_ICL 0 +#define CV_CPU_FORCE_AVX512_ICL 0 +#define CV_CPU_HAS_SUPPORT_AVX512_ICL 0 +#define CV_CPU_CALL_AVX512_ICL(fn, args) +#define CV_CPU_CALL_AVX512_ICL_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_AVX512_ICL(fn, args, mode, ...) \ + CV_CPU_CALL_AVX512_ICL(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_NEON +#define CV_TRY_NEON 1 +#define CV_CPU_FORCE_NEON 1 +#define CV_CPU_HAS_SUPPORT_NEON 1 +#define CV_CPU_CALL_NEON(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_NEON_(fn, args) return (opt_NEON::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_NEON +#define CV_TRY_NEON 1 +#define CV_CPU_FORCE_NEON 0 +#define CV_CPU_HAS_SUPPORT_NEON (cv::checkHardwareSupport(CV_CPU_NEON)) +#define CV_CPU_CALL_NEON(fn, args) \ + if (CV_CPU_HAS_SUPPORT_NEON) \ + return (opt_NEON::fn args) +#define CV_CPU_CALL_NEON_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_NEON) \ + return (opt_NEON::fn args) +#else +#define CV_TRY_NEON 0 +#define CV_CPU_FORCE_NEON 0 +#define CV_CPU_HAS_SUPPORT_NEON 0 +#define CV_CPU_CALL_NEON(fn, args) +#define CV_CPU_CALL_NEON_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_NEON(fn, args, mode, ...) \ + CV_CPU_CALL_NEON(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_NEON_DOTPROD +#define CV_TRY_NEON_DOTPROD 1 +#define CV_CPU_FORCE_NEON_DOTPROD 1 +#define CV_CPU_HAS_SUPPORT_NEON_DOTPROD 1 +#define CV_CPU_CALL_NEON_DOTPROD(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_NEON_DOTPROD_(fn, args) return (opt_NEON_DOTPROD::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_NEON_DOTPROD +#define CV_TRY_NEON_DOTPROD 1 +#define CV_CPU_FORCE_NEON_DOTPROD 0 +#define CV_CPU_HAS_SUPPORT_NEON_DOTPROD \ + (cv::checkHardwareSupport(CV_CPU_NEON_DOTPROD)) +#define CV_CPU_CALL_NEON_DOTPROD(fn, args) \ + if (CV_CPU_HAS_SUPPORT_NEON_DOTPROD) \ + return (opt_NEON_DOTPROD::fn args) +#define CV_CPU_CALL_NEON_DOTPROD_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_NEON_DOTPROD) \ + return (opt_NEON_DOTPROD::fn args) +#else +#define CV_TRY_NEON_DOTPROD 0 +#define CV_CPU_FORCE_NEON_DOTPROD 0 +#define CV_CPU_HAS_SUPPORT_NEON_DOTPROD 0 +#define CV_CPU_CALL_NEON_DOTPROD(fn, args) +#define CV_CPU_CALL_NEON_DOTPROD_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_NEON_DOTPROD(fn, args, mode, ...) \ + CV_CPU_CALL_NEON_DOTPROD(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_NEON_FP16 +#define CV_TRY_NEON_FP16 1 +#define CV_CPU_FORCE_NEON_FP16 1 +#define CV_CPU_HAS_SUPPORT_NEON_FP16 1 +#define CV_CPU_CALL_NEON_FP16(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_NEON_FP16_(fn, args) return (opt_NEON_FP16::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_NEON_FP16 +#define CV_TRY_NEON_FP16 1 +#define CV_CPU_FORCE_NEON_FP16 0 +#define CV_CPU_HAS_SUPPORT_NEON_FP16 \ + (cv::checkHardwareSupport(CV_CPU_NEON_FP16)) +#define CV_CPU_CALL_NEON_FP16(fn, args) \ + if (CV_CPU_HAS_SUPPORT_NEON_FP16) \ + return (opt_NEON_FP16::fn args) +#define CV_CPU_CALL_NEON_FP16_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_NEON_FP16) \ + return (opt_NEON_FP16::fn args) +#else +#define CV_TRY_NEON_FP16 0 +#define CV_CPU_FORCE_NEON_FP16 0 +#define CV_CPU_HAS_SUPPORT_NEON_FP16 0 +#define CV_CPU_CALL_NEON_FP16(fn, args) +#define CV_CPU_CALL_NEON_FP16_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_NEON_FP16(fn, args, mode, ...) \ + CV_CPU_CALL_NEON_FP16(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_NEON_BF16 +#define CV_TRY_NEON_BF16 1 +#define CV_CPU_FORCE_NEON_BF16 1 +#define CV_CPU_HAS_SUPPORT_NEON_BF16 1 +#define CV_CPU_CALL_NEON_BF16(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_NEON_BF16_(fn, args) return (opt_NEON_BF16::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_NEON_BF16 +#define CV_TRY_NEON_BF16 1 +#define CV_CPU_FORCE_NEON_BF16 0 +#define CV_CPU_HAS_SUPPORT_NEON_BF16 \ + (cv::checkHardwareSupport(CV_CPU_NEON_BF16)) +#define CV_CPU_CALL_NEON_BF16(fn, args) \ + if (CV_CPU_HAS_SUPPORT_NEON_BF16) \ + return (opt_NEON_BF16::fn args) +#define CV_CPU_CALL_NEON_BF16_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_NEON_BF16) \ + return (opt_NEON_BF16::fn args) +#else +#define CV_TRY_NEON_BF16 0 +#define CV_CPU_FORCE_NEON_BF16 0 +#define CV_CPU_HAS_SUPPORT_NEON_BF16 0 +#define CV_CPU_CALL_NEON_BF16(fn, args) +#define CV_CPU_CALL_NEON_BF16_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_NEON_BF16(fn, args, mode, ...) \ + CV_CPU_CALL_NEON_BF16(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_MSA +#define CV_TRY_MSA 1 +#define CV_CPU_FORCE_MSA 1 +#define CV_CPU_HAS_SUPPORT_MSA 1 +#define CV_CPU_CALL_MSA(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_MSA_(fn, args) return (opt_MSA::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_MSA +#define CV_TRY_MSA 1 +#define CV_CPU_FORCE_MSA 0 +#define CV_CPU_HAS_SUPPORT_MSA (cv::checkHardwareSupport(CV_CPU_MSA)) +#define CV_CPU_CALL_MSA(fn, args) \ + if (CV_CPU_HAS_SUPPORT_MSA) \ + return (opt_MSA::fn args) +#define CV_CPU_CALL_MSA_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_MSA) \ + return (opt_MSA::fn args) +#else +#define CV_TRY_MSA 0 +#define CV_CPU_FORCE_MSA 0 +#define CV_CPU_HAS_SUPPORT_MSA 0 +#define CV_CPU_CALL_MSA(fn, args) +#define CV_CPU_CALL_MSA_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_MSA(fn, args, mode, ...) \ + CV_CPU_CALL_MSA(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_VSX +#define CV_TRY_VSX 1 +#define CV_CPU_FORCE_VSX 1 +#define CV_CPU_HAS_SUPPORT_VSX 1 +#define CV_CPU_CALL_VSX(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_VSX_(fn, args) return (opt_VSX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_VSX +#define CV_TRY_VSX 1 +#define CV_CPU_FORCE_VSX 0 +#define CV_CPU_HAS_SUPPORT_VSX (cv::checkHardwareSupport(CV_CPU_VSX)) +#define CV_CPU_CALL_VSX(fn, args) \ + if (CV_CPU_HAS_SUPPORT_VSX) \ + return (opt_VSX::fn args) +#define CV_CPU_CALL_VSX_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_VSX) \ + return (opt_VSX::fn args) +#else +#define CV_TRY_VSX 0 +#define CV_CPU_FORCE_VSX 0 +#define CV_CPU_HAS_SUPPORT_VSX 0 +#define CV_CPU_CALL_VSX(fn, args) +#define CV_CPU_CALL_VSX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_VSX(fn, args, mode, ...) \ + CV_CPU_CALL_VSX(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_VSX3 +#define CV_TRY_VSX3 1 +#define CV_CPU_FORCE_VSX3 1 +#define CV_CPU_HAS_SUPPORT_VSX3 1 +#define CV_CPU_CALL_VSX3(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_VSX3_(fn, args) return (opt_VSX3::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_VSX3 +#define CV_TRY_VSX3 1 +#define CV_CPU_FORCE_VSX3 0 +#define CV_CPU_HAS_SUPPORT_VSX3 (cv::checkHardwareSupport(CV_CPU_VSX3)) +#define CV_CPU_CALL_VSX3(fn, args) \ + if (CV_CPU_HAS_SUPPORT_VSX3) \ + return (opt_VSX3::fn args) +#define CV_CPU_CALL_VSX3_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_VSX3) \ + return (opt_VSX3::fn args) +#else +#define CV_TRY_VSX3 0 +#define CV_CPU_FORCE_VSX3 0 +#define CV_CPU_HAS_SUPPORT_VSX3 0 +#define CV_CPU_CALL_VSX3(fn, args) +#define CV_CPU_CALL_VSX3_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_VSX3(fn, args, mode, ...) \ + CV_CPU_CALL_VSX3(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_RVV +#define CV_TRY_RVV 1 +#define CV_CPU_FORCE_RVV 1 +#define CV_CPU_HAS_SUPPORT_RVV 1 +#define CV_CPU_CALL_RVV(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_RVV_(fn, args) return (opt_RVV::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_RVV +#define CV_TRY_RVV 1 +#define CV_CPU_FORCE_RVV 0 +#define CV_CPU_HAS_SUPPORT_RVV (cv::checkHardwareSupport(CV_CPU_RVV)) +#define CV_CPU_CALL_RVV(fn, args) \ + if (CV_CPU_HAS_SUPPORT_RVV) \ + return (opt_RVV::fn args) +#define CV_CPU_CALL_RVV_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_RVV) \ + return (opt_RVV::fn args) +#else +#define CV_TRY_RVV 0 +#define CV_CPU_FORCE_RVV 0 +#define CV_CPU_HAS_SUPPORT_RVV 0 +#define CV_CPU_CALL_RVV(fn, args) +#define CV_CPU_CALL_RVV_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_RVV(fn, args, mode, ...) \ + CV_CPU_CALL_RVV(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_LSX +#define CV_TRY_LSX 1 +#define CV_CPU_FORCE_LSX 1 +#define CV_CPU_HAS_SUPPORT_LSX 1 +#define CV_CPU_CALL_LSX(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_LSX_(fn, args) return (opt_LSX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_LSX +#define CV_TRY_LSX 1 +#define CV_CPU_FORCE_LSX 0 +#define CV_CPU_HAS_SUPPORT_LSX (cv::checkHardwareSupport(CV_CPU_LSX)) +#define CV_CPU_CALL_LSX(fn, args) \ + if (CV_CPU_HAS_SUPPORT_LSX) \ + return (opt_LSX::fn args) +#define CV_CPU_CALL_LSX_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_LSX) \ + return (opt_LSX::fn args) +#else +#define CV_TRY_LSX 0 +#define CV_CPU_FORCE_LSX 0 +#define CV_CPU_HAS_SUPPORT_LSX 0 +#define CV_CPU_CALL_LSX(fn, args) +#define CV_CPU_CALL_LSX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_LSX(fn, args, mode, ...) \ + CV_CPU_CALL_LSX(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_COMPILE_LASX +#define CV_TRY_LASX 1 +#define CV_CPU_FORCE_LASX 1 +#define CV_CPU_HAS_SUPPORT_LASX 1 +#define CV_CPU_CALL_LASX(fn, args) return (cpu_baseline::fn args) +#define CV_CPU_CALL_LASX_(fn, args) return (opt_LASX::fn args) +#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && \ + defined CV_CPU_DISPATCH_COMPILE_LASX +#define CV_TRY_LASX 1 +#define CV_CPU_FORCE_LASX 0 +#define CV_CPU_HAS_SUPPORT_LASX (cv::checkHardwareSupport(CV_CPU_LASX)) +#define CV_CPU_CALL_LASX(fn, args) \ + if (CV_CPU_HAS_SUPPORT_LASX) \ + return (opt_LASX::fn args) +#define CV_CPU_CALL_LASX_(fn, args) \ + if (CV_CPU_HAS_SUPPORT_LASX) \ + return (opt_LASX::fn args) +#else +#define CV_TRY_LASX 0 +#define CV_CPU_FORCE_LASX 0 +#define CV_CPU_HAS_SUPPORT_LASX 0 +#define CV_CPU_CALL_LASX(fn, args) +#define CV_CPU_CALL_LASX_(fn, args) +#endif +#define __CV_CPU_DISPATCH_CHAIN_LASX(fn, args, mode, ...) \ + CV_CPU_CALL_LASX(fn, args); \ + __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_##mode(fn, args, __VA_ARGS__)) + +#define CV_CPU_CALL_BASELINE(fn, args) return (cpu_baseline::fn args) +#define __CV_CPU_DISPATCH_CHAIN_BASELINE(fn, args, mode, ...) \ + CV_CPU_CALL_BASELINE(fn, args) /* last in sequence */ diff --git a/third-party/include/opencv2/core/cvdef.h b/third-party/include/opencv2/core/cvdef.h new file mode 100644 index 0000000000..105a4c3386 --- /dev/null +++ b/third-party/include/opencv2/core/cvdef.h @@ -0,0 +1,1003 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this +license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright +notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote +products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" +and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are +disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any +direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_CVDEF_H +#define OPENCV_CORE_CVDEF_H + +#include "opencv2/core/version.hpp" + +//! @addtogroup core_utils +//! @{ + +#ifdef OPENCV_INCLUDE_PORT_FILE // User-provided header file with custom + // platform configuration +#include OPENCV_INCLUDE_PORT_FILE +#endif + +#if !defined CV_DOXYGEN && !defined CV_IGNORE_DEBUG_BUILD_GUARD +#if (defined(_MSC_VER) && (defined(DEBUG) || defined(_DEBUG))) || \ + (defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_DEBUG_PEDANTIC)) +// Guard to prevent using of binary incompatible binaries / runtimes +// https://github.com/opencv/opencv/pull/9161 +#define CV__DEBUG_NS_BEGIN namespace debug_build_guard { +#define CV__DEBUG_NS_END } +namespace cv { +namespace debug_build_guard {} +using namespace debug_build_guard; +} // namespace cv +#endif +#endif + +#ifndef CV__DEBUG_NS_BEGIN +#define CV__DEBUG_NS_BEGIN +#define CV__DEBUG_NS_END +#endif + +#ifdef __OPENCV_BUILD +#include "cvconfig.h" +#endif + +#ifndef __CV_EXPAND +#define __CV_EXPAND(x) x +#endif + +#ifndef __CV_CAT +#define __CV_CAT__(x, y) x##y +#define __CV_CAT_(x, y) __CV_CAT__(x, y) +#define __CV_CAT(x, y) __CV_CAT_(x, y) +#endif + +#define __CV_VA_NUM_ARGS_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, \ + ...) \ + N +#define __CV_VA_NUM_ARGS(...) \ + __CV_EXPAND( \ + __CV_VA_NUM_ARGS_HELPER(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) + +#ifdef CV_Func +// keep current value (through OpenCV port file) +#elif defined __GNUC__ || (defined(__cpluscplus) && (__cpluscplus >= 201103)) +#define CV_Func __func__ +#elif defined __clang__ && (__clang_minor__ * 100 + __clang_major__ >= 305) +#define CV_Func __func__ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION >= 199901) +#define CV_Func __func__ +#elif defined _MSC_VER +#define CV_Func __FUNCTION__ +#elif defined(__INTEL_COMPILER) && (_INTEL_COMPILER >= 600) +#define CV_Func __FUNCTION__ +#elif defined __IBMCPP__ && __IBMCPP__ >= 500 +#define CV_Func __FUNCTION__ +#elif defined __BORLAND__ && (__BORLANDC__ >= 0x550) +#define CV_Func __FUNC__ +#else +#define CV_Func "" +#endif + +//! @cond IGNORED + +//////////////// static assert ///////////////// +#define CVAUX_CONCAT_EXP(a, b) a##b +#define CVAUX_CONCAT(a, b) CVAUX_CONCAT_EXP(a, b) + +#if defined(__clang__) +#ifndef __has_extension +#define __has_extension \ + __has_feature /* compatibility, for older versions of clang */ +#endif +#if __has_extension(cxx_static_assert) +#define CV_StaticAssert(condition, reason) \ + static_assert((condition), reason " " #condition) +#elif __has_extension(c_static_assert) +#define CV_StaticAssert(condition, reason) \ + _Static_assert((condition), reason " " #condition) +#endif +#elif defined(__GNUC__) +#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) +#define CV_StaticAssert(condition, reason) \ + static_assert((condition), reason " " #condition) +#endif +#elif defined(_MSC_VER) +#if _MSC_VER >= 1600 /* MSVC 10 */ +#define CV_StaticAssert(condition, reason) \ + static_assert((condition), reason " " #condition) +#endif +#endif +#ifndef CV_StaticAssert +#if !defined(__clang__) && defined(__GNUC__) && \ + (__GNUC__ * 100 + __GNUC_MINOR__ > 302) +#define CV_StaticAssert(condition, reason) \ + ({ \ + extern int \ + __attribute__((error("CV_StaticAssert: " reason " " #condition))) \ + CV_StaticAssert(); \ + ((condition) ? 0 : CV_StaticAssert()); \ + }) +#else +namespace cv { +template struct CV_StaticAssert_failed; +template <> struct CV_StaticAssert_failed { + enum { val = 1 }; +}; +template struct CV_StaticAssert_test {}; +} // namespace cv +#define CV_StaticAssert(condition, reason) \ + typedef cv::CV_StaticAssert_test(condition)>)> \ + CVAUX_CONCAT(CV_StaticAssert_failed_at_, __LINE__) +#endif +#endif + +// Suppress warning "-Wdeprecated-declarations" / C4996 +#if defined(_MSC_VER) +#define CV_DO_PRAGMA(x) __pragma(x) +#elif defined(__GNUC__) +#define CV_DO_PRAGMA(x) _Pragma(#x) +#else +#define CV_DO_PRAGMA(x) +#endif + +#ifdef _MSC_VER +#define CV_SUPPRESS_DEPRECATED_START \ + CV_DO_PRAGMA(warning(push)) \ + CV_DO_PRAGMA(warning(disable : 4996)) +#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(warning(pop)) +#elif defined(__clang__) || \ + ((__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ > 405)) +#define CV_SUPPRESS_DEPRECATED_START \ + CV_DO_PRAGMA(GCC diagnostic push) \ + CV_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations") +#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(GCC diagnostic pop) +#else +#define CV_SUPPRESS_DEPRECATED_START +#define CV_SUPPRESS_DEPRECATED_END +#endif + +#define CV_UNUSED(name) (void)name + +//! @endcond + +// undef problematic defines sometimes defined by system headers (windows.h in +// particular) +#undef small +#undef min +#undef max +#undef abs +#undef Complex + +#if defined __cplusplus +#include +#else +#include +#endif + +#include "opencv2/core/hal/interface.h" + +#if defined __ICL +#define CV_ICC __ICL +#elif defined __ICC +#define CV_ICC __ICC +#elif defined __ECL +#define CV_ICC __ECL +#elif defined __ECC +#define CV_ICC __ECC +#elif defined __INTEL_COMPILER +#define CV_ICC __INTEL_COMPILER +#endif + +#if defined _WIN32 +#define CV_CDECL __cdecl +#define CV_STDCALL __stdcall +#else +#define CV_CDECL +#define CV_STDCALL +#endif + +#ifndef CV_INLINE +#if defined __cplusplus +#define CV_INLINE static inline +#elif defined _MSC_VER +#define CV_INLINE __inline +#else +#define CV_INLINE static +#endif +#endif + +#ifndef CV_ALWAYS_INLINE +#if defined(__GNUC__) && \ + (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define CV_ALWAYS_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define CV_ALWAYS_INLINE __forceinline +#else +#define CV_ALWAYS_INLINE inline +#endif +#endif + +#if defined CV_DISABLE_OPTIMIZATION || \ + (defined CV_ICC && !defined CV_ENABLE_UNROLLED) +#define CV_ENABLE_UNROLLED 0 +#else +#define CV_ENABLE_UNROLLED 1 +#endif + +#ifdef __GNUC__ +#define CV_DECL_ALIGNED(x) __attribute__((aligned(x))) +#elif defined _MSC_VER +#define CV_DECL_ALIGNED(x) __declspec(align(x)) +#else +#define CV_DECL_ALIGNED(x) +#endif + +/* CPU features and intrinsics support */ +#define CV_CPU_NONE 0 +#define CV_CPU_MMX 1 +#define CV_CPU_SSE 2 +#define CV_CPU_SSE2 3 +#define CV_CPU_SSE3 4 +#define CV_CPU_SSSE3 5 +#define CV_CPU_SSE4_1 6 +#define CV_CPU_SSE4_2 7 +#define CV_CPU_POPCNT 8 +#define CV_CPU_FP16 9 +#define CV_CPU_AVX 10 +#define CV_CPU_AVX2 11 +#define CV_CPU_FMA3 12 + +#define CV_CPU_AVX_512F 13 +#define CV_CPU_AVX_512BW 14 +#define CV_CPU_AVX_512CD 15 +#define CV_CPU_AVX_512DQ 16 +#define CV_CPU_AVX_512ER 17 +#define CV_CPU_AVX_512IFMA512 18 // deprecated +#define CV_CPU_AVX_512IFMA 18 +#define CV_CPU_AVX_512PF 19 +#define CV_CPU_AVX_512VBMI 20 +#define CV_CPU_AVX_512VL 21 +#define CV_CPU_AVX_512VBMI2 22 +#define CV_CPU_AVX_512VNNI 23 +#define CV_CPU_AVX_512BITALG 24 +#define CV_CPU_AVX_512VPOPCNTDQ 25 +#define CV_CPU_AVX_5124VNNIW 26 +#define CV_CPU_AVX_5124FMAPS 27 + +#define CV_CPU_NEON 100 +#define CV_CPU_NEON_DOTPROD 101 +#define CV_CPU_NEON_FP16 102 +#define CV_CPU_NEON_BF16 103 + +#define CV_CPU_MSA 150 + +#define CV_CPU_RISCVV 170 + +#define CV_CPU_VSX 200 +#define CV_CPU_VSX3 201 + +#define CV_CPU_RVV 210 + +#define CV_CPU_LSX 230 +#define CV_CPU_LASX 231 + +// CPU features groups +#define CV_CPU_AVX512_SKX 256 +#define CV_CPU_AVX512_COMMON 257 +#define CV_CPU_AVX512_KNL 258 +#define CV_CPU_AVX512_KNM 259 +#define CV_CPU_AVX512_CNL 260 +#define CV_CPU_AVX512_CLX 261 +#define CV_CPU_AVX512_ICL 262 + +// when adding to this list remember to update the following enum +#define CV_HARDWARE_MAX_FEATURE 512 + +/** @brief Available CPU features. + */ +enum CpuFeatures { + CPU_MMX = 1, + CPU_SSE = 2, + CPU_SSE2 = 3, + CPU_SSE3 = 4, + CPU_SSSE3 = 5, + CPU_SSE4_1 = 6, + CPU_SSE4_2 = 7, + CPU_POPCNT = 8, + CPU_FP16 = 9, + CPU_AVX = 10, + CPU_AVX2 = 11, + CPU_FMA3 = 12, + + CPU_AVX_512F = 13, + CPU_AVX_512BW = 14, + CPU_AVX_512CD = 15, + CPU_AVX_512DQ = 16, + CPU_AVX_512ER = 17, + CPU_AVX_512IFMA512 = 18, // deprecated + CPU_AVX_512IFMA = 18, + CPU_AVX_512PF = 19, + CPU_AVX_512VBMI = 20, + CPU_AVX_512VL = 21, + CPU_AVX_512VBMI2 = 22, + CPU_AVX_512VNNI = 23, + CPU_AVX_512BITALG = 24, + CPU_AVX_512VPOPCNTDQ = 25, + CPU_AVX_5124VNNIW = 26, + CPU_AVX_5124FMAPS = 27, + + CPU_NEON = 100, + CPU_NEON_DOTPROD = 101, + CPU_NEON_FP16 = 102, + CPU_NEON_BF16 = 103, + + CPU_MSA = 150, + + CPU_RISCVV = 170, + + CPU_VSX = 200, + CPU_VSX3 = 201, + + CPU_RVV = 210, + + CPU_LSX = 230, + CPU_LASX = 231, + + CPU_AVX512_SKX = 256, //!< Skylake-X with AVX-512F/CD/BW/DQ/VL + CPU_AVX512_COMMON = 257, //!< Common instructions AVX-512F/CD for all CPUs + //!< that support AVX-512 + CPU_AVX512_KNL = 258, //!< Knights Landing with AVX-512F/CD/ER/PF + CPU_AVX512_KNM = + 259, //!< Knights Mill with AVX-512F/CD/ER/PF/4FMAPS/4VNNIW/VPOPCNTDQ + CPU_AVX512_CNL = 260, //!< Cannon Lake with AVX-512F/CD/BW/DQ/VL/IFMA/VBMI + CPU_AVX512_CLX = 261, //!< Cascade Lake with AVX-512F/CD/BW/DQ/VL/VNNI + CPU_AVX512_ICL = + 262, //!< Ice Lake with + //!< AVX-512F/CD/BW/DQ/VL/IFMA/VBMI/VNNI/VBMI2/BITALG/VPOPCNTDQ + + CPU_MAX_FEATURE = 512 // see CV_HARDWARE_MAX_FEATURE +}; + +#include "cv_cpu_dispatch.h" + +#if !defined(CV_STRONG_ALIGNMENT) && defined(__arm__) && \ + !(defined(__aarch64__) || defined(_M_ARM64)) +// int*, int64* should be propertly aligned pointers on ARMv7 +#define CV_STRONG_ALIGNMENT 1 +#endif +#if !defined(CV_STRONG_ALIGNMENT) +#define CV_STRONG_ALIGNMENT 0 +#endif + +/* fundamental constants */ +#define CV_PI 3.1415926535897932384626433832795 +#define CV_2PI 6.283185307179586476925286766559 +#define CV_LOG2 0.69314718055994530941723212145818 + +#if defined __ARM_FP16_FORMAT_IEEE && !defined __CUDACC__ +#define CV_FP16_TYPE 1 +#else +#define CV_FP16_TYPE 0 +#endif + +typedef union Cv16suf { + short i; + ushort u; +#if CV_FP16_TYPE + __fp16 h; +#endif +} Cv16suf; + +typedef union Cv32suf { + int i; + unsigned u; + float f; +} Cv32suf; + +typedef union Cv64suf { + int64 i; + uint64 u; + double f; +} Cv64suf; + +#ifndef OPENCV_ABI_COMPATIBILITY +#define OPENCV_ABI_COMPATIBILITY 400 +#endif + +#ifdef __OPENCV_BUILD +#define DISABLE_OPENCV_3_COMPATIBILITY +#define OPENCV_DISABLE_DEPRECATED_COMPATIBILITY +#endif + +#ifndef CV_EXPORTS +#if (defined _WIN32 || defined WINCE || defined __CYGWIN__) && \ + defined(CVAPI_EXPORTS) +#define CV_EXPORTS __declspec(dllexport) +#elif defined __GNUC__ && __GNUC__ >= 4 && \ + (defined(CVAPI_EXPORTS) || defined(__APPLE__)) +#define CV_EXPORTS __attribute__((visibility("default"))) +#endif +#endif + +#ifndef CV_EXPORTS +#define CV_EXPORTS +#endif + +#ifdef _MSC_VER +#define CV_EXPORTS_TEMPLATE +#else +#define CV_EXPORTS_TEMPLATE CV_EXPORTS +#endif + +#ifndef CV_DEPRECATED +#if defined(__GNUC__) +#define CV_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define CV_DEPRECATED __declspec(deprecated) +#else +#define CV_DEPRECATED +#endif +#endif + +#ifndef CV_DEPRECATED_EXTERNAL +#if defined(__OPENCV_BUILD) +#define CV_DEPRECATED_EXTERNAL /* nothing */ +#else +#define CV_DEPRECATED_EXTERNAL CV_DEPRECATED +#endif +#endif + +#ifndef CV_EXTERN_C +#ifdef __cplusplus +#define CV_EXTERN_C extern "C" +#else +#define CV_EXTERN_C +#endif +#endif + +/* special informative macros for wrapper generators */ +#define CV_EXPORTS_W CV_EXPORTS +#define CV_EXPORTS_W_SIMPLE CV_EXPORTS +#define CV_EXPORTS_AS(synonym) CV_EXPORTS +#define CV_EXPORTS_W_MAP CV_EXPORTS +#define CV_EXPORTS_W_PARAMS CV_EXPORTS +#define CV_IN_OUT +#define CV_OUT +#define CV_PROP +#define CV_PROP_RW +#define CV_ND // Indicates that input data should be parsed into Mat without + // channels +#define CV_WRAP +#define CV_WRAP_AS(synonym) +#define CV_WRAP_MAPPABLE(mappable) +#define CV_WRAP_PHANTOM(phantom_header) +#define CV_WRAP_DEFAULT(val) +/* Indicates that the function parameter has filesystem path semantic */ +#define CV_WRAP_FILE_PATH + +/****************************************************************************************\ +* Matrix type (Mat) * +\****************************************************************************************/ + +#define CV_MAX_DIM 32 +#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) +#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) +#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX * CV_CN_MAX - 1) +#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK) +#define CV_MAT_CONT_FLAG_SHIFT 14 +#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT) +#define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG) +#define CV_IS_CONT_MAT CV_IS_MAT_CONT +#define CV_SUBMAT_FLAG_SHIFT 15 +#define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT) +#define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG) + +/** Size of each channel item, + 0x28442211 = 0010 1000 0100 0100 0010 0010 0001 0001 ~ array of + sizeof(arr_type_elem) */ +#define CV_ELEM_SIZE1(type) ((0x28442211 >> CV_MAT_DEPTH(type) * 4) & 15) + +#define CV_ELEM_SIZE(type) (CV_MAT_CN(type) * CV_ELEM_SIZE1(type)) + +#ifndef MIN +#define MIN(a, b) ((a) > (b) ? (b) : (a)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#endif + +/** min & max without jumps */ +#define CV_IMIN(a, b) ((a) ^ (((a) ^ (b)) & (((a) < (b)) - 1))) +#define CV_IMAX(a, b) ((a) ^ (((a) ^ (b)) & (((a) > (b)) - 1))) +#define CV_SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define CV_CMP(a, b) (((a) > (b)) - ((a) < (b))) +#define CV_SIGN(a) CV_CMP((a), 0) + +///////////////////////////////////////// Enum operators +////////////////////////////////////////// + +/** + +Provides compatibility operators for both classical and C++11 enum classes, +as well as exposing the C++11 enum class members for backwards compatibility + +@code + // Provides operators required for flag enums + CV_ENUM_FLAGS(AccessFlag) + + // Exposes the listed members of the enum class AccessFlag to the current +namespace CV_ENUM_CLASS_EXPOSE(AccessFlag, ACCESS_READ [, ACCESS_WRITE [, ...] +]); +@endcode +*/ + +#define __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST) \ + static const EnumType MEMBER_CONST = EnumType::MEMBER_CONST; + +#define __CV_ENUM_CLASS_EXPOSE_2(EnumType, MEMBER_CONST, ...) \ + __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ + __CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_1(EnumType, __VA_ARGS__)); + +#define __CV_ENUM_CLASS_EXPOSE_3(EnumType, MEMBER_CONST, ...) \ + __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ + __CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_2(EnumType, __VA_ARGS__)); + +#define __CV_ENUM_CLASS_EXPOSE_4(EnumType, MEMBER_CONST, ...) \ + __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ + __CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_3(EnumType, __VA_ARGS__)); + +#define __CV_ENUM_CLASS_EXPOSE_5(EnumType, MEMBER_CONST, ...) \ + __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ + __CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_4(EnumType, __VA_ARGS__)); + +#define __CV_ENUM_CLASS_EXPOSE_6(EnumType, MEMBER_CONST, ...) \ + __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ + __CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_5(EnumType, __VA_ARGS__)); + +#define __CV_ENUM_CLASS_EXPOSE_7(EnumType, MEMBER_CONST, ...) \ + __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ + __CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_6(EnumType, __VA_ARGS__)); + +#define __CV_ENUM_CLASS_EXPOSE_8(EnumType, MEMBER_CONST, ...) \ + __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ + __CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_7(EnumType, __VA_ARGS__)); + +#define __CV_ENUM_CLASS_EXPOSE_9(EnumType, MEMBER_CONST, ...) \ + __CV_ENUM_CLASS_EXPOSE_1(EnumType, MEMBER_CONST); \ + __CV_EXPAND(__CV_ENUM_CLASS_EXPOSE_8(EnumType, __VA_ARGS__)); + +#define __CV_ENUM_FLAGS_LOGICAL_NOT(EnumType) \ + static inline bool operator!(const EnumType &val) { \ + typedef std::underlying_type::type UnderlyingType; \ + return !static_cast(val); \ + } + +#define __CV_ENUM_FLAGS_LOGICAL_NOT_EQ(Arg1Type, Arg2Type) \ + static inline bool operator!=(const Arg1Type &a, const Arg2Type &b) { \ + return static_cast(a) != static_cast(b); \ + } + +#define __CV_ENUM_FLAGS_LOGICAL_EQ(Arg1Type, Arg2Type) \ + static inline bool operator==(const Arg1Type &a, const Arg2Type &b) { \ + return static_cast(a) == static_cast(b); \ + } + +#define __CV_ENUM_FLAGS_BITWISE_NOT(EnumType) \ + static inline EnumType operator~(const EnumType &val) { \ + typedef std::underlying_type::type UnderlyingType; \ + return static_cast(~static_cast(val)); \ + } + +#define __CV_ENUM_FLAGS_BITWISE_OR(EnumType, Arg1Type, Arg2Type) \ + static inline EnumType operator|(const Arg1Type &a, const Arg2Type &b) { \ + typedef std::underlying_type::type UnderlyingType; \ + return static_cast(static_cast(a) | \ + static_cast(b)); \ + } + +#define __CV_ENUM_FLAGS_BITWISE_AND(EnumType, Arg1Type, Arg2Type) \ + static inline EnumType operator&(const Arg1Type &a, const Arg2Type &b) { \ + typedef std::underlying_type::type UnderlyingType; \ + return static_cast(static_cast(a) & \ + static_cast(b)); \ + } + +#define __CV_ENUM_FLAGS_BITWISE_XOR(EnumType, Arg1Type, Arg2Type) \ + static inline EnumType operator^(const Arg1Type &a, const Arg2Type &b) { \ + typedef std::underlying_type::type UnderlyingType; \ + return static_cast(static_cast(a) ^ \ + static_cast(b)); \ + } + +#define __CV_ENUM_FLAGS_BITWISE_OR_EQ(EnumType, Arg1Type) \ + static inline EnumType &operator|=(EnumType &_this, const Arg1Type &val) { \ + _this = static_cast(static_cast(_this) | \ + static_cast(val)); \ + return _this; \ + } + +#define __CV_ENUM_FLAGS_BITWISE_AND_EQ(EnumType, Arg1Type) \ + static inline EnumType &operator&=(EnumType &_this, const Arg1Type &val) { \ + _this = static_cast(static_cast(_this) & \ + static_cast(val)); \ + return _this; \ + } + +#define __CV_ENUM_FLAGS_BITWISE_XOR_EQ(EnumType, Arg1Type) \ + static inline EnumType &operator^=(EnumType &_this, const Arg1Type &val) { \ + _this = static_cast(static_cast(_this) ^ \ + static_cast(val)); \ + return _this; \ + } + +#define CV_ENUM_CLASS_EXPOSE(EnumType, ...) \ + __CV_EXPAND(__CV_CAT(__CV_ENUM_CLASS_EXPOSE_, \ + __CV_VA_NUM_ARGS(__VA_ARGS__))(EnumType, __VA_ARGS__)); + +#define CV_ENUM_FLAGS(EnumType) \ + __CV_ENUM_FLAGS_LOGICAL_NOT(EnumType) \ + __CV_ENUM_FLAGS_LOGICAL_EQ(EnumType, int) \ + __CV_ENUM_FLAGS_LOGICAL_NOT_EQ(EnumType, int) \ + \ + __CV_ENUM_FLAGS_BITWISE_NOT(EnumType) \ + __CV_ENUM_FLAGS_BITWISE_OR(EnumType, EnumType, EnumType) \ + __CV_ENUM_FLAGS_BITWISE_AND(EnumType, EnumType, EnumType) \ + __CV_ENUM_FLAGS_BITWISE_XOR(EnumType, EnumType, EnumType) \ + \ + __CV_ENUM_FLAGS_BITWISE_OR_EQ(EnumType, EnumType) \ + __CV_ENUM_FLAGS_BITWISE_AND_EQ(EnumType, EnumType) \ + __CV_ENUM_FLAGS_BITWISE_XOR_EQ(EnumType, EnumType) + +/****************************************************************************************\ +* static analysys * +\****************************************************************************************/ + +// In practice, some macro are not processed correctly (noreturn is not +// detected). We need to use simplified definition for them. +#ifndef CV_STATIC_ANALYSIS +#if defined(__KLOCWORK__) || defined(__clang_analyzer__) || \ + defined(__COVERITY__) +#define CV_STATIC_ANALYSIS 1 +#endif +#else +#if defined(CV_STATIC_ANALYSIS) && \ + !(__CV_CAT(1, CV_STATIC_ANALYSIS) == 1) // defined and not empty +#if 0 == CV_STATIC_ANALYSIS +#undef CV_STATIC_ANALYSIS +#endif +#endif +#endif + +/****************************************************************************************\ +* Thread sanitizer * +\****************************************************************************************/ +#ifndef CV_THREAD_SANITIZER +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#define CV_THREAD_SANITIZER +#endif +#endif +#endif + +/****************************************************************************************\ +* exchange-add operation for atomic operations on reference counters * +\****************************************************************************************/ + +#ifdef CV_XADD +// allow to use user-defined macro +#elif defined __GNUC__ || defined __clang__ +#if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && \ + !defined __EMSCRIPTEN__ && !defined(__CUDACC__) && \ + !defined __INTEL_COMPILER +#ifdef __ATOMIC_ACQ_REL +#define CV_XADD(addr, delta) \ + __c11_atomic_fetch_add((_Atomic(int) *)(addr), delta, __ATOMIC_ACQ_REL) +#else +#define CV_XADD(addr, delta) \ + __atomic_fetch_add((_Atomic(int) *)(addr), delta, 4) +#endif +#else +#if defined __ATOMIC_ACQ_REL && !defined __clang__ +// version for gcc >= 4.7 +#define CV_XADD(addr, delta) \ + (int)__atomic_fetch_add((unsigned *)(addr), (unsigned)(delta), \ + __ATOMIC_ACQ_REL) +#else +#define CV_XADD(addr, delta) \ + (int)__sync_fetch_and_add((unsigned *)(addr), (unsigned)(delta)) +#endif +#endif +#elif defined _MSC_VER && !defined RC_INVOKED +#include +#define CV_XADD(addr, delta) \ + (int)_InterlockedExchangeAdd((long volatile *)addr, delta) +#else +#ifdef OPENCV_FORCE_UNSAFE_XADD +CV_INLINE int CV_XADD(int *addr, int delta) { + int tmp = *addr; + *addr += delta; + return tmp; +} +#else +#error \ + "OpenCV: can't define safe CV_XADD macro for current platform (unsupported). Define CV_XADD macro through custom port header (see OPENCV_INCLUDE_PORT_FILE)" +#endif +#endif + +/****************************************************************************************\ +* CV_NORETURN attribute * +\****************************************************************************************/ + +#ifndef CV_NORETURN +#if defined(__GNUC__) +#define CV_NORETURN __attribute__((__noreturn__)) +#elif defined(_MSC_VER) && (_MSC_VER >= 1300) +#define CV_NORETURN __declspec(noreturn) +#else +#define CV_NORETURN /* nothing by default */ +#endif +#endif + +/****************************************************************************************\ +* CV_NODISCARD_STD attribute (C++17) * +* encourages the compiler to issue a warning if the return value is discarded * +\****************************************************************************************/ +#ifndef CV_NODISCARD_STD +#ifndef __has_cpp_attribute +// workaround preprocessor non-compliance https://reviews.llvm.org/D57851 +#define __has_cpp_attribute(__x) 0 +#endif +#if __has_cpp_attribute(nodiscard) +#if defined(__NVCC__) && __CUDACC_VER_MAJOR__ < 12 +#define CV_NODISCARD_STD +#else +#define CV_NODISCARD_STD [[nodiscard]] +#endif +#elif __cplusplus >= 201703L +// available when compiler is C++17 compliant +#define CV_NODISCARD_STD [[nodiscard]] +#elif defined(__INTEL_COMPILER) +// see above, available when C++17 is enabled +#elif defined(_MSC_VER) && _MSC_VER >= 1911 && _MSVC_LANG >= 201703L +// available with VS2017 v15.3+ with /std:c++17 or higher; works on functions +// and classes +#define CV_NODISCARD_STD [[nodiscard]] +#elif defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 700) && \ + (__cplusplus >= 201103L) +// available with GCC 7.0+; works on functions, works or silently fails on +// classes +#define CV_NODISCARD_STD [[nodiscard]] +#elif defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 408) && \ + (__cplusplus >= 201103L) +// available with GCC 4.8+ but it usually does nothing and can fail noisily -- +// therefore not used define CV_NODISCARD_STD [[gnu::warn_unused_result]] +#endif +#endif +#ifndef CV_NODISCARD_STD +#define CV_NODISCARD_STD /* nothing by default */ +#endif + +/****************************************************************************************\ +* C++ 11 * +\****************************************************************************************/ +#ifdef __cplusplus +// MSVC was stuck at __cplusplus == 199711L for a long time, even where it +// supports C++11, so check _MSC_VER instead. See: +// +#if defined(_MSC_VER) +#if _MSC_VER < 1800 +#error "OpenCV 4.x+ requires enabled C++11 support" +#endif +#elif __cplusplus < 201103L +#error "OpenCV 4.x+ requires enabled C++11 support" +#endif +#endif + +#ifndef CV_CXX11 +#define CV_CXX11 1 +#endif + +#ifndef CV_OVERRIDE +#define CV_OVERRIDE override +#endif + +#ifndef CV_FINAL +#define CV_FINAL final +#endif + +#ifndef CV_NOEXCEPT +#define CV_NOEXCEPT noexcept +#endif + +#ifndef CV_CONSTEXPR +#define CV_CONSTEXPR constexpr +#endif + +// Integer types portability +#ifdef __cplusplus +#include +namespace cv { +using std::int16_t; +using std::int32_t; +using std::int64_t; +using std::int8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; +using std::uint8_t; +} // namespace cv +#else // pure C +#include +#endif + +#ifdef __cplusplus +namespace cv { + +class hfloat { +public: +#if CV_FP16_TYPE + + hfloat() : h(0) {} + explicit hfloat(float x) { h = (__fp16)x; } + operator float() const { return (float)h; } + +protected: + __fp16 h; + +#else + hfloat() : w(0) {} + explicit hfloat(float x) { +#if CV_FP16 && CV_AVX2 + __m128 v = _mm_load_ss(&x); + w = (ushort)_mm_cvtsi128_si32(_mm_cvtps_ph(v, 0)); +#else + Cv32suf in; + in.f = x; + unsigned sign = in.u & 0x80000000; + in.u ^= sign; + + if (in.u >= 0x47800000) + w = (ushort)(in.u > 0x7f800000 ? 0x7e00 : 0x7c00); + else { + if (in.u < 0x38800000) { + in.f += 0.5f; + w = (ushort)(in.u - 0x3f000000); + } else { + unsigned t = in.u + 0xc8000fff; + w = (ushort)((t + ((in.u >> 13) & 1)) >> 13); + } + } + + w = (ushort)(w | (sign >> 16)); +#endif + } + + operator float() const { +#if CV_FP16 && CV_AVX2 + float f; + _mm_store_ss(&f, _mm_cvtph_ps(_mm_cvtsi32_si128(w))); + return f; +#else + Cv32suf out; + + unsigned t = ((w & 0x7fff) << 13) + 0x38000000; + unsigned sign = (w & 0x8000) << 16; + unsigned e = w & 0x7c00; + + out.u = t + (1 << 23); + out.u = (e >= 0x7c00 ? t + 0x38000000 + : e == 0 ? (static_cast(out.f -= 6.103515625e-05f), out.u) + : t) | + sign; + return out.f; +#endif + } + +protected: + ushort w; + +#endif +}; + +inline hfloat hfloatFromBits(ushort w) { +#if CV_FP16_TYPE + Cv16suf u; + u.u = w; + hfloat res(float(u.h)); + return res; +#else + Cv32suf out; + + unsigned t = ((w & 0x7fff) << 13) + 0x38000000; + unsigned sign = (w & 0x8000) << 16; + unsigned e = w & 0x7c00; + + out.u = t + (1 << 23); + out.u = (e >= 0x7c00 ? t + 0x38000000 + : e == 0 ? (static_cast(out.f -= 6.103515625e-05f), out.u) + : t) | + sign; + hfloat res(out.f); + return res; +#endif +} + +#if !defined(__OPENCV_BUILD) && !(defined __STDCPP_FLOAT16_T__) && \ + !(defined __ARM_NEON) +typedef hfloat float16_t; +#endif + +} // namespace cv +#endif + +/** @brief Constructs the 'fourcc' code, used in video codecs and many other + places. Simply call it with 4 chars like `CV_FOURCC('I', 'Y', 'U', 'V')` +*/ +CV_INLINE int CV_FOURCC(char c1, char c2, char c3, char c4) { + return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + + ((c4 & 255) << 24); +} + +//! Macro to construct the fourcc code of the codec. Same as CV_FOURCC() +#define CV_FOURCC_MACRO(c1, c2, c3, c4) \ + (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + \ + (((c4) & 255) << 24)) + +//! @} + +#ifndef __cplusplus +#include "opencv2/core/fast_math.hpp" // define cvRound(double) +#endif + +#define CV_OCL_RUN_(condition, func, ...) +#define CV_OCL_RUN(condition, func) CV_OCL_RUN_(condition, func) + +#define CV_OVX_RUN(condition, func, ...) + +#endif // OPENCV_CORE_CVDEF_H diff --git a/third-party/include/opencv2/core/cvstd.hpp b/third-party/include/opencv2/core/cvstd.hpp new file mode 100644 index 0000000000..481cf8da1f --- /dev/null +++ b/third-party/include/opencv2/core/cvstd.hpp @@ -0,0 +1,196 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this +license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright +notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote +products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" +and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are +disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any +direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_CVSTD_HPP +#define OPENCV_CORE_CVSTD_HPP + +#ifndef __cplusplus +#error cvstd.hpp header must be compiled as C++ +#endif + +#include "opencv2/core/cvdef.h" +#include +#include +#include + +#include + +// import useful primitives from stl +#include +#include +#include //for abs(int) +#include + +namespace cv { +static inline uchar abs(uchar a) { return a; } +static inline ushort abs(ushort a) { return a; } +static inline unsigned abs(unsigned a) { return a; } +static inline uint64 abs(uint64 a) { return a; } + +using std::abs; +using std::exp; +using std::log; +using std::max; +using std::min; +using std::pow; +using std::sqrt; +using std::swap; +} // namespace cv + +#include "cvstd_wrapper.hpp" + +namespace cv { + +//! @addtogroup core_utils +//! @{ + +//////////////////////////// memory management functions +/////////////////////////////// + +/** @brief Allocates an aligned memory buffer. + +The function allocates the buffer of the specified size and returns it. When the +buffer size is 16 bytes or more, the returned buffer is aligned to 16 bytes. +@param bufSize Allocated buffer size. + */ +CV_EXPORTS void *fastMalloc(size_t bufSize); + +/** @brief Deallocates a memory buffer. + +The function deallocates the buffer allocated with fastMalloc . If NULL pointer +is passed, the function does nothing. C version of the function clears the +pointer *pptr* to avoid problems with double memory deallocation. +@param ptr Pointer to the allocated buffer. + */ +CV_EXPORTS void fastFree(void *ptr); + +/*! + The STL-compliant memory Allocator based on cv::fastMalloc() and + cv::fastFree() +*/ +template class Allocator { +public: + typedef _Tp value_type; + typedef value_type *pointer; + typedef const value_type *const_pointer; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + template class rebind { + typedef Allocator other; + }; + + explicit Allocator() {} + ~Allocator() {} + explicit Allocator(Allocator const &) {} + template explicit Allocator(Allocator const &) {} + + // address + pointer address(reference r) { return &r; } + const_pointer address(const_reference r) { return &r; } + + pointer allocate(size_type count, const void * = 0) { + return reinterpret_cast(fastMalloc(count * sizeof(_Tp))); + } + void deallocate(pointer p, size_type) { fastFree(p); } + + void construct(pointer p, const _Tp &v) { + new (static_cast(p)) _Tp(v); + } + void destroy(pointer p) { p->~_Tp(); } + + size_type max_size() const { + return cv::max(static_cast<_Tp>(-1) / sizeof(_Tp), 1); + } +}; + +//! @} core_utils + +//! @addtogroup core_basic +//! @{ + +//////////////////////////////// string class //////////////////////////////// + +class CV_EXPORTS FileNode; // for string constructor from FileNode + +typedef std::string String; + +#ifndef OPENCV_DISABLE_STRING_LOWER_UPPER_CONVERSIONS + +//! @cond IGNORED +namespace details { +// std::tolower is int->int +static inline char char_tolower(char ch) { return (char)std::tolower((int)ch); } +// std::toupper is int->int +static inline char char_toupper(char ch) { return (char)std::toupper((int)ch); } +} // namespace details +//! @endcond + +static inline std::string toLowerCase(const std::string &str) { + std::string result(str); + std::transform(result.begin(), result.end(), result.begin(), + details::char_tolower); + return result; +} + +static inline std::string toUpperCase(const std::string &str) { + std::string result(str); + std::transform(result.begin(), result.end(), result.begin(), + details::char_toupper); + return result; +} + +#endif // OPENCV_DISABLE_STRING_LOWER_UPPER_CONVERSIONS + +//! @} core_basic +} // namespace cv + +#endif // OPENCV_CORE_CVSTD_HPP diff --git a/third-party/include/opencv2/core/cvstd.inl.hpp b/third-party/include/opencv2/core/cvstd.inl.hpp new file mode 100644 index 0000000000..0a18f75698 --- /dev/null +++ b/third-party/include/opencv2/core/cvstd.inl.hpp @@ -0,0 +1,188 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this +license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without +modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright +notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote +products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" +and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are +disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any +direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_CORE_CVSTDINL_HPP +#define OPENCV_CORE_CVSTDINL_HPP + +#include +#include +#include + +//! @cond IGNORED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + +namespace cv { + +template class DataType> { +public: + typedef std::complex<_Tp> value_type; + typedef value_type work_type; + typedef _Tp channel_type; + + enum { + generic_type = 0, + depth = DataType::depth, + channels = 2, + fmt = DataType::fmt + ((channels - 1) << 8), + type = CV_MAKETYPE(depth, channels) + }; + + typedef Vec vec_type; +}; + +static inline std::ostream &operator<<(std::ostream &out, Ptr fmtd) { + fmtd->reset(); + for (const char *str = fmtd->next(); str; str = fmtd->next()) + out << str; + return out; +} + +static inline std::ostream &operator<<(std::ostream &out, const Mat &mtx) { + return out << Formatter::get()->format(mtx); +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const Complex<_Tp> &c) { + return out << "(" << c.re << "," << c.im << ")"; +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const std::vector> &vec) { + return out << Formatter::get()->format(Mat(vec)); +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const std::vector> &vec) { + return out << Formatter::get()->format(Mat(vec)); +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const Matx<_Tp, m, n> &matx) { + return out << Formatter::get()->format(Mat(matx)); +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const Point_<_Tp> &p) { + out << "[" << p.x << ", " << p.y << "]"; + return out; +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const Point3_<_Tp> &p) { + out << "[" << p.x << ", " << p.y << ", " << p.z << "]"; + return out; +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const Vec<_Tp, n> &vec) { + out << "["; + if (cv::traits::Depth<_Tp>::value <= CV_32S) { + for (int i = 0; i < n - 1; ++i) { + out << (int)vec[i] << ", "; + } + out << (int)vec[n - 1] << "]"; + } else { + for (int i = 0; i < n - 1; ++i) { + out << vec[i] << ", "; + } + out << vec[n - 1] << "]"; + } + + return out; +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const Size_<_Tp> &size) { + return out << "[" << size.width << " x " << size.height << "]"; +} + +template +static inline std::ostream &operator<<(std::ostream &out, + const Rect_<_Tp> &rect) { + return out << "[" << rect.width << " x " << rect.height << " from (" << rect.x + << ", " << rect.y << ")]"; +} + +static inline std::ostream &operator<<(std::ostream &out, + const MatSize &msize) { + int i, dims = msize.dims(); + for (i = 0; i < dims; i++) { + out << msize[i]; + if (i < dims - 1) + out << " x "; + } + return out; +} + +static inline std::ostream &operator<<(std::ostream &s, cv::Range &r) { + return s << "[" << r.start << " : " << r.end << ")"; +} + +} // namespace cv + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +//! @endcond + +#endif // OPENCV_CORE_CVSTDINL_HPP diff --git a/third-party/include/opencv2/core/cvstd_wrapper.hpp b/third-party/include/opencv2/core/cvstd_wrapper.hpp new file mode 100644 index 0000000000..8725beb753 --- /dev/null +++ b/third-party/include/opencv2/core/cvstd_wrapper.hpp @@ -0,0 +1,187 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_CVSTD_WRAPPER_HPP +#define OPENCV_CORE_CVSTD_WRAPPER_HPP + +#include "opencv2/core/cvdef.h" + +#include // std::shared_ptr +#include +#include // std::enable_if + +namespace cv { + +using std::nullptr_t; + +//! @addtogroup core_basic +//! @{ + +#ifdef CV_DOXYGEN + +template +using Ptr = + std::shared_ptr<_Tp>; // In ideal world it should look like this, but we + // need some compatibility workarounds below + +template +static inline Ptr<_Tp> makePtr(const A1 &...a1) { + return std::make_shared<_Tp>(a1...); +} + +#else // cv::Ptr with compatibility workarounds + +// It should be defined for C-API types only. +// C++ types should use regular "delete" operator. +template struct DefaultDeleter; +#if 0 +{ + void operator()(Y* p) const; +}; +#endif + +namespace sfinae { +template +struct has_parenthesis_operator { +private: + template + static CV_CONSTEXPR std::true_type has_parenthesis_operator_check( + typename std::is_same< + typename std::decay().operator()( + std::declval()...))>::type, + Ret>::type *); + + template + static CV_CONSTEXPR std::false_type has_parenthesis_operator_check(...); + + typedef decltype(has_parenthesis_operator_check(0)) type; + +public: +#if __cplusplus >= 201103L || \ + (defined(_MSC_VER) && _MSC_VER >= 1900 /*MSVS 2015*/) + static CV_CONSTEXPR bool value = type::value; +#else + // support MSVS 2013 + static const int value = type::value; +#endif +}; +} // namespace sfinae + +template +struct has_custom_delete : public std::false_type {}; + +// Force has_custom_delete to std::false_type when NVCC is compiling CUDA source +// files +#ifndef __CUDACC__ +template +struct has_custom_delete< + T, typename std::enable_if, void, T *>::value>::type> + : public std::true_type {}; +#endif + +template struct Ptr : public std::shared_ptr { +#if 0 + using std::shared_ptr::shared_ptr; // GCC 5.x can't handle this +#else + inline Ptr() CV_NOEXCEPT : std::shared_ptr() {} + inline Ptr(nullptr_t) CV_NOEXCEPT : std::shared_ptr(nullptr) {} + template + inline Ptr(Y *p, D d) : std::shared_ptr(p, d) {} + template + inline Ptr(nullptr_t, D d) : std::shared_ptr(nullptr, d) {} + + template + inline Ptr(const Ptr &r, T *ptr) CV_NOEXCEPT : std::shared_ptr(r, ptr) { + } + + inline Ptr(const Ptr &o) CV_NOEXCEPT : std::shared_ptr(o) {} + inline Ptr(Ptr &&o) CV_NOEXCEPT : std::shared_ptr(std::move(o)) {} + + template + inline Ptr(const Ptr &o) CV_NOEXCEPT : std::shared_ptr(o) {} + template + inline Ptr(Ptr &&o) CV_NOEXCEPT : std::shared_ptr(std::move(o)) {} +#endif + inline Ptr(const std::shared_ptr &o) CV_NOEXCEPT : std::shared_ptr(o) {} + inline Ptr(std::shared_ptr &&o) CV_NOEXCEPT + : std::shared_ptr(std::move(o)) {} + + // Overload with custom DefaultDeleter: Ptr(...) + template + inline Ptr(const std::true_type &, Y *ptr) + : std::shared_ptr(ptr, DefaultDeleter()) {} + + // Overload without custom deleter: Ptr(...); + template + inline Ptr(const std::false_type &, Y *ptr) : std::shared_ptr(ptr) {} + + template + inline Ptr(Y *ptr) : Ptr(has_custom_delete(), ptr) {} + + // Overload with custom DefaultDeleter: Ptr(...) + template inline void reset(const std::true_type &, Y *ptr) { + std::shared_ptr::reset(ptr, DefaultDeleter()); + } + + // Overload without custom deleter: Ptr(...); + template inline void reset(const std::false_type &, Y *ptr) { + std::shared_ptr::reset(ptr); + } + + template inline void reset(Y *ptr) { + Ptr::reset(has_custom_delete(), ptr); + } + + template void reset(Y *ptr, Deleter d) { + std::shared_ptr::reset(ptr, d); + } + + void reset() CV_NOEXCEPT { std::shared_ptr::reset(); } + + Ptr &operator=(const Ptr &o) { + std::shared_ptr::operator=(o); + return *this; + } + template inline Ptr &operator=(const Ptr &o) { + std::shared_ptr::operator=(o); + return *this; + } + + T *operator->() const CV_NOEXCEPT { return std::shared_ptr::get(); } + typename std::add_lvalue_reference::type operator*() const CV_NOEXCEPT { + return *std::shared_ptr::get(); + } + + // OpenCV 3.x methods (not a part of standard C++ library) + inline void release() { std::shared_ptr::reset(); } + inline operator T *() const { return std::shared_ptr::get(); } + inline bool empty() const { return std::shared_ptr::get() == nullptr; } + + template inline Ptr staticCast() const CV_NOEXCEPT { + return std::static_pointer_cast(*this); + } + + template inline Ptr constCast() const CV_NOEXCEPT { + return std::const_pointer_cast(*this); + } + + template inline Ptr dynamicCast() const CV_NOEXCEPT { + return std::dynamic_pointer_cast(*this); + } +}; + +template +static inline Ptr<_Tp> makePtr(const A1 &...a1) { + static_assert(!has_custom_delete<_Tp>::value, + "Can't use this makePtr with custom DefaultDeleter"); + return (Ptr<_Tp>)std::make_shared<_Tp>(a1...); +} + +#endif // CV_DOXYGEN + +//! @} core_basic +} // namespace cv + +#endif // OPENCV_CORE_CVSTD_WRAPPER_HPP diff --git a/third-party/include/opencv2/core/detail/async_promise.hpp b/third-party/include/opencv2/core/detail/async_promise.hpp new file mode 100644 index 0000000000..1367275498 --- /dev/null +++ b/third-party/include/opencv2/core/detail/async_promise.hpp @@ -0,0 +1,73 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_ASYNC_PROMISE_HPP +#define OPENCV_CORE_ASYNC_PROMISE_HPP + +#include "../async.hpp" + +#include "exception_ptr.hpp" + +namespace cv { + +/** @addtogroup core_async +@{ +*/ + +/** @brief Provides result of asynchronous operations + +*/ +class CV_EXPORTS AsyncPromise { +public: + ~AsyncPromise() CV_NOEXCEPT; + AsyncPromise() CV_NOEXCEPT; + explicit AsyncPromise(const AsyncPromise &o) CV_NOEXCEPT; + AsyncPromise &operator=(const AsyncPromise &o) CV_NOEXCEPT; + void release() CV_NOEXCEPT; + + /** Returns associated AsyncArray + @note Can be called once + */ + AsyncArray getArrayResult(); + + /** Stores asynchronous result. + @param[in] value result + */ + void setValue(InputArray value); + + // TODO "move" setters + +#if CV__EXCEPTION_PTR + /** Stores exception. + @param[in] exception exception to be raised in AsyncArray + */ + void setException(std::exception_ptr exception); +#endif + + /** Stores exception. + @param[in] exception exception to be raised in AsyncArray + */ + void setException(const cv::Exception &exception); + + explicit AsyncPromise(AsyncPromise &&o) { + p = o.p; + o.p = NULL; + } + AsyncPromise &operator=(AsyncPromise &&o) CV_NOEXCEPT { + std::swap(p, o.p); + return *this; + } + + // PImpl + typedef struct AsyncArray::Impl Impl; + friend struct AsyncArray::Impl; + inline void *_getImpl() const CV_NOEXCEPT { return p; } + +protected: + Impl *p; +}; + +//! @} +} // namespace cv +#endif // OPENCV_CORE_ASYNC_PROMISE_HPP diff --git a/third-party/include/opencv2/core/detail/dispatch_helper.impl.hpp b/third-party/include/opencv2/core/detail/dispatch_helper.impl.hpp new file mode 100644 index 0000000000..e4ccc39e96 --- /dev/null +++ b/third-party/include/opencv2/core/detail/dispatch_helper.impl.hpp @@ -0,0 +1,48 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CORE_DETAIL_DISPATCH_HELPER_IMPL_HPP +#define OPENCV_CORE_DETAIL_DISPATCH_HELPER_IMPL_HPP + +//! @cond IGNORED + +namespace cv { +namespace detail { + +template