react-native-executorch 0.10.6 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/lib/module/fetcher/telemetry.js +1 -1
  2. package/package.json +1 -1
  3. package/react-native-executorch.podspec +2 -0
  4. package/src/fetcher/telemetry.ts +1 -1
  5. package/third-party/common/phonemis/CMakeLists.txt +70 -14
  6. package/third-party/common/phonemis/README.md +183 -33
  7. package/third-party/common/phonemis/THIRD_PARTY_NOTICES.md +57 -0
  8. package/third-party/common/phonemis/knowledge/code_style.md +642 -0
  9. package/third-party/common/phonemis/licenses/Unicode-3.0.txt +39 -0
  10. package/third-party/common/phonemis/licenses/misaki-Apache-2.0.txt +201 -0
  11. package/third-party/common/phonemis/licenses/nlohmann-json-MIT.txt +21 -0
  12. package/third-party/common/phonemis/licenses/xsimd-BSD-3-Clause.txt +29 -0
  13. package/third-party/common/phonemis/src/phonemis/base/config.h +6 -0
  14. package/third-party/common/phonemis/src/phonemis/base/ipipeline.cpp +75 -0
  15. package/third-party/common/phonemis/src/phonemis/base/ipipeline.h +21 -0
  16. package/third-party/common/phonemis/src/phonemis/base/phonemizer/constants.h +2 -5
  17. package/third-party/common/phonemis/src/phonemis/base/phonemizer/lexicon_phonemizer.cpp +3 -4
  18. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.cpp +17 -8
  19. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.h +4 -0
  20. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.cpp +21 -6
  21. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.h +13 -4
  22. package/third-party/common/phonemis/src/phonemis/base/pipeline.cpp +8 -0
  23. package/third-party/common/phonemis/src/phonemis/base/pipeline.h +19 -0
  24. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.cpp +37 -0
  25. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.h +45 -0
  26. package/third-party/common/phonemis/src/phonemis/base/processor/common/constants.h +10 -0
  27. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.cpp +105 -0
  28. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.h +49 -0
  29. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.cpp +173 -0
  30. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.h +67 -0
  31. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.cpp +75 -0
  32. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.h +60 -0
  33. package/third-party/common/phonemis/src/phonemis/base/processor/common/types.h +18 -0
  34. package/third-party/common/phonemis/src/phonemis/base/processor/config.h +53 -0
  35. package/third-party/common/phonemis/src/phonemis/base/processor/layer.h +9 -7
  36. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/constants.h +20 -0
  37. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.cpp +89 -0
  38. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.h +35 -0
  39. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/types.h +16 -0
  40. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/kind.h +40 -0
  41. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/layer.h +382 -0
  42. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/notation.h +30 -0
  43. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.cpp +51 -0
  44. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.h +31 -0
  45. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern.h +30 -0
  46. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.cpp +17 -0
  47. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.h +31 -0
  48. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.cpp +811 -0
  49. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.h +285 -0
  50. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.cpp +64 -0
  51. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.h +23 -0
  52. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/types.h +94 -0
  53. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sanitizer/layer.cpp +19 -0
  54. package/third-party/common/phonemis/src/phonemis/base/processor/{sanitizer_layer.h → layers/sanitizer/layer.h} +8 -8
  55. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.cpp +65 -0
  56. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.h +29 -0
  57. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.cpp +170 -0
  58. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.h +40 -0
  59. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/types.h +25 -0
  60. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.cpp +47 -0
  61. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.h +19 -0
  62. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.cpp +60 -0
  63. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.h +45 -0
  64. package/third-party/common/phonemis/src/phonemis/base/processor/processor.cpp +6 -7
  65. package/third-party/common/phonemis/src/phonemis/base/processor/processor.h +14 -10
  66. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.cpp +89 -52
  67. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.h +16 -9
  68. package/third-party/common/phonemis/src/phonemis/base/tokenizer/tokenizer.cpp +13 -12
  69. package/third-party/common/phonemis/src/phonemis/lang/de/constants.h +183 -19
  70. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.cpp +355 -309
  71. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.h +42 -17
  72. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.cpp +56 -0
  73. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.h +15 -0
  74. package/third-party/common/phonemis/src/phonemis/lang/de/pipeline.h +3 -3
  75. package/third-party/common/phonemis/src/phonemis/lang/en/constants.h +181 -30
  76. package/third-party/common/phonemis/src/phonemis/lang/en/hmm_tagger.cpp +5 -7
  77. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.cpp +232 -135
  78. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.h +41 -16
  79. package/third-party/common/phonemis/src/phonemis/lang/en/pipeline.h +3 -10
  80. package/third-party/common/phonemis/src/phonemis/lang/es/constants.h +182 -60
  81. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.cpp +247 -212
  82. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.h +38 -18
  83. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.cpp +50 -0
  84. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.h +15 -0
  85. package/third-party/common/phonemis/src/phonemis/lang/es/pipeline.h +3 -3
  86. package/third-party/common/phonemis/src/phonemis/lang/fr/constants.h +152 -26
  87. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.cpp +252 -179
  88. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.h +38 -15
  89. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.cpp +83 -0
  90. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.h +15 -0
  91. package/third-party/common/phonemis/src/phonemis/lang/fr/pipeline.h +3 -3
  92. package/third-party/common/phonemis/src/phonemis/lang/hi/constants.h +62 -10
  93. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.cpp +74 -123
  94. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.h +27 -16
  95. package/third-party/common/phonemis/src/phonemis/lang/hi/pipeline.h +5 -3
  96. package/third-party/common/phonemis/src/phonemis/lang/it/constants.h +122 -42
  97. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.cpp +200 -207
  98. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.h +30 -18
  99. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.cpp +25 -0
  100. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.h +15 -0
  101. package/third-party/common/phonemis/src/phonemis/lang/it/pipeline.h +3 -3
  102. package/third-party/common/phonemis/src/phonemis/lang/pl/constants.h +346 -77
  103. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.cpp +631 -246
  104. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.h +47 -15
  105. package/third-party/common/phonemis/src/phonemis/lang/pl/pipeline.h +6 -6
  106. package/third-party/common/phonemis/src/phonemis/lang/pt/constants.h +201 -0
  107. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.cpp +365 -0
  108. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.h +53 -0
  109. package/third-party/common/phonemis/src/phonemis/lang/pt/pipeline.h +4 -2
  110. package/third-party/common/phonemis/src/phonemis/main.cpp +42 -11
  111. package/third-party/common/phonemis/src/phonemis/protophone/meta.h +24 -0
  112. package/third-party/common/phonemis/src/phonemis/protophone/numeric.h +26 -0
  113. package/third-party/common/phonemis/src/phonemis/protophone/protophone.cpp +525 -0
  114. package/third-party/common/phonemis/src/phonemis/protophone/protophone.h +80 -0
  115. package/third-party/common/phonemis/src/phonemis/protophone/tensor.h +76 -0
  116. package/third-party/common/phonemis/src/phonemis/protophone/tensor_utils.h +89 -0
  117. package/third-party/common/phonemis/src/phonemis/protophone/tensor_view.h +125 -0
  118. package/third-party/common/phonemis/src/phonemis/protophone/types.h +43 -0
  119. package/third-party/common/phonemis/src/phonemis/utils/strings.h +20 -14
  120. package/third-party/common/phonemis/src/phonemis/utils/unicode.h +15 -1
  121. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_arithmetic.hpp +267 -0
  122. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_bit.hpp +232 -0
  123. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_cast.hpp +43 -0
  124. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_complex.hpp +112 -0
  125. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_details.hpp +386 -0
  126. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_logical.hpp +240 -0
  127. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_math.hpp +2601 -0
  128. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_memory.hpp +1006 -0
  129. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_rounding.hpp +72 -0
  130. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_swizzle.hpp +260 -0
  131. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_trigo.hpp +996 -0
  132. package/third-party/common/phonemis/src/third-party/xsimd/arch/utils/shifts.hpp +82 -0
  133. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx.hpp +2111 -0
  134. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2.hpp +1591 -0
  135. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2_128.hpp +170 -0
  136. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512bw.hpp +724 -0
  137. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512cd.hpp +28 -0
  138. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512dq.hpp +270 -0
  139. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512er.hpp +17 -0
  140. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512f.hpp +2919 -0
  141. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512ifma.hpp +17 -0
  142. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512pf.hpp +17 -0
  143. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi.hpp +76 -0
  144. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi2.hpp +130 -0
  145. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512bw.hpp +17 -0
  146. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512vbmi2.hpp +17 -0
  147. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx_128.hpp +164 -0
  148. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avxvnni.hpp +17 -0
  149. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common.hpp +26 -0
  150. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common_fwd.hpp +127 -0
  151. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_constants.hpp +393 -0
  152. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_emulated.hpp +787 -0
  153. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx.hpp +93 -0
  154. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx2.hpp +46 -0
  155. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_sse.hpp +97 -0
  156. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma4.hpp +92 -0
  157. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_i8mm_neon64.hpp +17 -0
  158. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_isa.hpp +148 -0
  159. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon.hpp +3580 -0
  160. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon64.hpp +1614 -0
  161. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_rvv.hpp +1515 -0
  162. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_scalar.hpp +1210 -0
  163. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse2.hpp +2333 -0
  164. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse3.hpp +66 -0
  165. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_1.hpp +510 -0
  166. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_2.hpp +44 -0
  167. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_ssse3.hpp +186 -0
  168. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sve.hpp +1186 -0
  169. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vsx.hpp +947 -0
  170. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vxe.hpp +787 -0
  171. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_wasm.hpp +1819 -0
  172. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_arch.hpp +242 -0
  173. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_config.hpp +633 -0
  174. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features.hpp +50 -0
  175. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_arm.hpp +132 -0
  176. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_ppc.hpp +54 -0
  177. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_riscv.hpp +95 -0
  178. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_s390x.hpp +56 -0
  179. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_x86.hpp +1121 -0
  180. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpuid.hpp +144 -0
  181. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_getauxval.hpp +159 -0
  182. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_macros.hpp +78 -0
  183. package/third-party/common/phonemis/src/third-party/xsimd/math/xsimd_rem_pio2.hpp +707 -0
  184. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_aligned_allocator.hpp +349 -0
  185. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_alignment.hpp +102 -0
  186. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_all_registers.hpp +57 -0
  187. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_api.hpp +3106 -0
  188. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx2_register.hpp +57 -0
  189. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512bw_register.hpp +51 -0
  190. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512cd_register.hpp +51 -0
  191. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512dq_register.hpp +51 -0
  192. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512er_register.hpp +51 -0
  193. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512f_register.hpp +77 -0
  194. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512ifma_register.hpp +51 -0
  195. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512pf_register.hpp +51 -0
  196. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi2_register.hpp +51 -0
  197. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi_register.hpp +51 -0
  198. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512bw_register.hpp +54 -0
  199. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512vbmi2_register.hpp +53 -0
  200. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx_register.hpp +79 -0
  201. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avxvnni_register.hpp +44 -0
  202. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch.hpp +1666 -0
  203. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_constant.hpp +572 -0
  204. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_fwd.hpp +41 -0
  205. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_common_arch.hpp +49 -0
  206. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_emulated_register.hpp +80 -0
  207. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx2_register.hpp +50 -0
  208. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx_register.hpp +50 -0
  209. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_sse_register.hpp +50 -0
  210. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma4_register.hpp +50 -0
  211. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_i8mm_neon64_register.hpp +55 -0
  212. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon64_register.hpp +55 -0
  213. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon_register.hpp +130 -0
  214. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_register.hpp +96 -0
  215. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_rvv_register.hpp +491 -0
  216. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse2_register.hpp +59 -0
  217. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse3_register.hpp +49 -0
  218. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_1_register.hpp +48 -0
  219. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_2_register.hpp +48 -0
  220. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_ssse3_register.hpp +48 -0
  221. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sve_register.hpp +216 -0
  222. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_traits.hpp +409 -0
  223. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_utils.hpp +462 -0
  224. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vsx_register.hpp +84 -0
  225. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vxe_register.hpp +86 -0
  226. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_wasm_register.hpp +59 -0
  227. package/third-party/common/phonemis/src/third-party/xsimd/utils/bits.hpp +122 -0
  228. package/third-party/common/phonemis/src/third-party/xsimd/utils/xsimd_type_traits.hpp +145 -0
  229. package/third-party/common/phonemis/src/third-party/xsimd/xsimd.hpp +43 -0
  230. package/third-party/common/phonemis/src/phonemis/base/processor/constants.h +0 -11
  231. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/config.h +0 -16
  232. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.cpp +0 -271
  233. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.h +0 -45
  234. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/types.h +0 -29
  235. package/third-party/common/phonemis/src/phonemis/base/processor/sanitizer_layer.cpp +0 -22
  236. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.cpp +0 -40
  237. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.h +0 -22
@@ -1,393 +1,439 @@
1
- #include "num2word.h"
2
1
  #include "constants.h"
3
- #include <phonemis/base/processor/constants.h>
4
- #include <phonemis/utils/conversions.h>
2
+ #include "num2word.h"
3
+ #include "patterns.h"
4
+ #include <phonemis/base/processor/layers/num2word/numerals.h>
5
+ #include <phonemis/base/processor/layers/num2word/patterns.h>
6
+ #include <phonemis/base/processor/layers/num2word/primitives.h>
7
+ #include <phonemis/utils/strings.h>
5
8
  #include <phonemis/utils/unicode.h>
6
- #include <algorithm>
7
- #include <cctype>
8
- #include <cmath>
9
- #include <cstdlib>
9
+
10
+ #include <array>
10
11
 
11
12
  namespace phonemis::de {
12
13
 
13
- using namespace constants;
14
- using namespace phonemis::utils;
15
- using processor::num2word::Mode;
16
- using processor::num2word::StringifiedNumber;
14
+ using namespace constants::num2word;
15
+ using namespace processor;
16
+ using namespace processor::num2word;
17
+ using namespace utils;
17
18
 
18
19
  namespace {
19
- // Checks if a character serves as a word boundary.
20
- bool is_boundary(char32_t c) {
21
- return !utils::unicode::isalnum(c) && c != U'_';
20
+ uint64_t value(const Number& number) {
21
+ return value_of(number.integer).value_or(0);
22
22
  }
23
23
 
24
- // Counts and returns the number of consecutive digits from the start index
25
- size_t count_digits(std::u32string_view input, size_t start) {
26
- auto it = std::find_if(
27
- input.begin() + start, input.end(),
28
- [](char32_t c) { return !utils::unicode::isdigit(c); });
29
- return static_cast<size_t>(it - (input.begin() + start));
24
+ // ------------------------
25
+ // ----- Number words -----
26
+ // ------------------------
27
+
28
+ std::u32string cardinal(uint64_t n);
29
+
30
+ // A cardinal as the first part of a compound: ein, einundzwanzig, einhundertein
31
+ std::u32string stem(uint64_t n) {
32
+ std::u32string words = cardinal(n);
33
+ return words.ends_with(U"eins") ? words.substr(0, words.size() - 1) : words;
30
34
  }
31
35
 
32
- // Checks if a character is a known currency symbol.
33
- bool is_currency(char32_t c) {
34
- for (auto sym : processor::constants::kCurrencies) {
35
- if (c == sym) return true;
36
+ std::u32string cardinal(uint64_t n) {
37
+ if (n < 20) {
38
+ return std::u32string(kOnes[n]);
39
+ }
40
+ if (n < 100) {
41
+ return (n % 10 ? stem(n % 10) + U"und" : U"") + std::u32string(kTens[n / 10]);
42
+ }
43
+ if (n < 1000) {
44
+ return stem(n / 100) + U"hundert" + (n % 100 ? cardinal(n % 100) : U"");
45
+ }
46
+ if (n < 1000000) {
47
+ return stem(n / 1000) + U"tausend" + (n % 1000 ? cardinal(n % 1000) : U"");
48
+ }
49
+ for (auto [scale, one, many] :
50
+ {std::tuple{1000000000ULL, U"Milliarde", U"Milliarden"}, std::tuple{1000000ULL, U"Million", U"Millionen"}}) {
51
+ if (n >= scale) {
52
+ uint64_t q = n / scale, r = n % scale;
53
+ std::u32string head = q == 1 ? U"eine " + std::u32string(one) : cardinal(q) + U" " + std::u32string(many);
54
+ return head + (r ? U" " + cardinal(r) : U"");
55
+ }
36
56
  }
37
- return false;
57
+ return U"";
38
58
  }
39
59
 
40
- bool has_nominative_article(std::u32string_view input, size_t start) {
41
- size_t pos = start;
42
- while (pos > 0 && utils::unicode::isspace(input[pos - 1])) {
43
- pos--;
60
+ // 1100-1999 in hundreds (neunzehnhundertneunzig); later years read like cardinals
61
+ std::u32string year(uint64_t n) {
62
+ if (n >= 1100 && n <= 1999) {
63
+ return cardinal(n / 100) + U"hundert" + (n % 100 ? cardinal(n % 100) : U"");
44
64
  }
45
- size_t end = pos;
46
- while (pos > 0 && utils::unicode::isalpha(input[pos - 1])) {
47
- pos--;
65
+ return cardinal(n);
66
+ }
67
+
68
+ std::u32string ordinal(uint64_t n, std::u32string_view ending) {
69
+ std::u32string words = cardinal(n);
70
+ uint64_t r = n % 100;
71
+ if (r > 0 && r < 20) {
72
+ std::u32string one(kOnes[r]);
73
+ auto it = kOrdinalStems.find(one);
74
+ std::u32string base = words.substr(0, words.size() - one.size());
75
+ return base + (it != kOrdinalStems.end() ? it->second : one) + U"t" + std::u32string(ending);
48
76
  }
49
- if (pos == end) return false;
77
+ return words + U"st" + std::u32string(ending);
78
+ }
50
79
 
51
- std::u32string word(input.substr(pos, end - pos));
52
- for (auto& ch : word) {
53
- ch = utils::unicode::tolower(ch);
80
+ std::u32string digits(std::u32string_view text) {
81
+ std::vector<std::u32string> words;
82
+ for (char32_t c : text) {
83
+ words.emplace_back(kOnes[c - U'0']);
54
84
  }
85
+ return join(words);
86
+ }
55
87
 
56
- return word == U"der" || word == U"die" || word == U"das" ||
57
- word == U"ein" || word == U"eine";
88
+ // "1" said like an article, by case and gender: eine Stunde, mit einem Mal
89
+ std::u32string article(Case c, Gender g) {
90
+ static const std::array<std::array<std::u32string_view, 3>, 4> forms = {{
91
+ {U"ein", U"eine", U"ein"}, // Nominative
92
+ {U"eines", U"einer", U"eines"}, // Genitive
93
+ {U"einem", U"einer", U"einem"}, // Dative
94
+ {U"einen", U"eine", U"ein"}, // Accusative
95
+ }};
96
+ size_t row = c == Case::GENITIVE ? 1 : c == Case::DATIVE ? 2 : c == Case::ACCUSATIVE ? 3 : 0;
97
+ return std::u32string(forms[row][static_cast<size_t>(g)]);
58
98
  }
59
- } // namespace
60
99
 
61
- std::u32string Num2Word::transform(std::u32string_view input) const {
62
- char32_t dec_sep = decimal_separator();
63
- std::u32string owned;
64
- std::u32string_view work = input;
65
- if (dec_sep != U'.') {
66
- owned.reserve(input.size());
67
- for (size_t i = 0; i < input.size(); ++i) {
68
- if (input[i] == dec_sep && i > 0 && i + 1 < input.size() &&
69
- utils::unicode::isdigit(input[i - 1]) && utils::unicode::isdigit(input[i + 1])) {
70
- owned.push_back(U'.');
71
- } else {
72
- owned.push_back(input[i]);
73
- }
74
- }
75
- work = owned;
100
+ // The adjective ending of an ordinal: am dritten, der dritte, ein zweiter, dritter
101
+ std::u32string_view ending(const NumberReading& reading) {
102
+ static const std::array<std::array<std::u32string_view, 3>, 4> strong = {{
103
+ {U"er", U"e", U"es"}, // Nominative
104
+ {U"en", U"er", U"en"}, // Genitive
105
+ {U"em", U"er", U"em"}, // Dative
106
+ {U"en", U"e", U"es"}, // Accusative
107
+ }};
108
+ switch (reading.declension) {
109
+ case Declension::WEAK:
110
+ return reading.grammatical_case == Case::NOMINATIVE ? U"e" : U"en";
111
+ case Declension::MIXED:
112
+ return reading.gender == Gender::NEUTER ? U"es" : U"er";
113
+ default:
114
+ Case c = reading.grammatical_case;
115
+ size_t row = c == Case::GENITIVE ? 1 : c == Case::DATIVE ? 2 : c == Case::ACCUSATIVE ? 3 : 0;
116
+ return strong[row][static_cast<size_t>(reading.gender)];
76
117
  }
118
+ }
77
119
 
78
- std::u32string result;
79
- result.reserve(work.size());
80
-
81
- size_t last_pos = 0;
82
- for (size_t i = 0; i < work.size(); ++i) {
83
- if (!utils::unicode::isdigit(work[i])) continue;
84
- if (i > 0 && !is_boundary(work[i - 1])) continue;
85
-
86
- size_t start = i;
87
- size_t len = 0;
88
- Mode mode = Mode::CARDINAL;
89
-
90
- size_t p1 = count_digits(work, start);
91
- size_t curr = start + p1;
92
-
93
- if (curr < work.size() && (work[curr] == U'.' || work[curr] == U'-' || work[curr] == U'/')) {
94
- char32_t sep = work[curr];
95
- size_t p2 = count_digits(work, curr + 1);
96
-
97
- if (p2 > 0) {
98
- size_t next_curr = curr + 1 + p2;
99
-
100
- if (next_curr < work.size() && work[next_curr] == sep && (sep == U'.' || sep == U'-')) {
101
- size_t p3 = count_digits(work, next_curr + 1);
102
- if (p3 > 0 &&
103
- (next_curr + 1 + p3 == work.size() || is_boundary(work[next_curr + 1 + p3]))) {
104
- if (p1 <= 4 && p2 <= 2 && p3 <= 4) {
105
- len = next_curr + 1 + p3 - start;
106
- mode = Mode::DATE;
107
- }
108
- }
109
- }
120
+ // -------------------
121
+ // ----- Context -----
122
+ // -------------------
110
123
 
111
- if (len == 0 && (curr + 1 + p2 == work.size() || is_boundary(work[curr + 1 + p2]))) {
112
- len = curr + 1 + p2 - start;
113
- size_t after = start + len;
114
- if (sep != U'/' && after < work.size() && is_currency(work[after]) &&
115
- (after + 1 == work.size() || is_boundary(work[after + 1]))) {
116
- len++;
117
- mode = Mode::CURRENCY;
118
- } else {
119
- mode = (sep == U'/') ? Mode::FRACTION : Mode::CARDINAL;
120
- }
121
- }
122
- } else if (sep == U'.') {
123
- len = p1 + 1;
124
- mode = Mode::ORDINAL;
124
+ Gender gender_of(std::u32string_view noun) {
125
+ std::u32string word = strings::to_lower(noun);
125
126
 
126
- size_t next_pos = start + len;
127
- while (next_pos < work.size() && utils::unicode::isspace(work[next_pos])) {
128
- next_pos++;
129
- }
130
- bool next_is_word = (next_pos < work.size()) && utils::unicode::isalpha(work[next_pos]);
131
- if (!config_.allow_general_ord_notation || !next_is_word) {
132
- mode = Mode::CARDINAL;
133
- len--;
134
- }
135
- }
127
+ // The longest known ending decides, then the regular ones
128
+ size_t longest = 0;
129
+ Gender gender = Gender::MASCULINE;
130
+ for (const auto& [key, key_gender] : kGenders) {
131
+ if (key.size() > longest && word.ends_with(key)) {
132
+ longest = key.size();
133
+ gender = key_gender;
136
134
  }
135
+ }
136
+ if (longest > 0) {
137
+ return gender;
138
+ }
137
139
 
138
- if (len == 0) {
139
- if (curr < work.size() && is_currency(work[curr]) &&
140
- (curr + 1 == work.size() || is_boundary(work[curr + 1]))) {
141
- len = p1 + 1;
142
- mode = Mode::CURRENCY;
143
- } else {
144
- size_t alpha = 0;
145
- while (curr + alpha < work.size() && utils::unicode::isalpha(work[curr + alpha])) {
146
- alpha++;
147
- }
148
-
149
- if (alpha > 0 && (curr + alpha == work.size() || is_boundary(work[curr + alpha]))) {
150
- len = p1 + alpha;
151
- mode = Mode::POTENTIALLY_ORDINAL;
152
- } else if (curr == work.size() || is_boundary(work[curr])) {
153
- len = p1;
154
- mode = Mode::CARDINAL;
155
- }
156
- }
157
- }
140
+ auto ends_with_any = [&](const std::vector<std::u32string>& endings) {
141
+ return std::ranges::any_of(endings, [&](const auto& e) { return word.ends_with(e); });
142
+ };
143
+ return ends_with_any(kFeminineEndings) ? Gender::FEMININE :
144
+ ends_with_any(kNeuterEndings) ? Gender::NEUTER :
145
+ Gender::MASCULINE;
146
+ }
158
147
 
159
- if (len > 0) {
160
- result.append(work.substr(last_pos, start - last_pos));
161
-
162
- if (mode == Mode::DATE) {
163
- char32_t sep = (work.substr(start, len).find(U'.') != std::u32string_view::npos) ? U'.' : U'-';
164
- size_t first_sep = work.find(sep, start);
165
- size_t second_sep = work.find(sep, first_sep + 1);
166
-
167
- std::u32string_view p1 = work.substr(start, first_sep - start);
168
- std::u32string_view p2 = work.substr(first_sep + 1, second_sep - first_sep - 1);
169
- std::u32string_view p3 = work.substr(second_sep + 1, start + len - second_sep - 1);
170
-
171
- auto val1 = as_int(p1);
172
- auto val2 = as_int(p2);
173
- auto val3 = as_int(p3);
174
-
175
- if (!val1 || !val2 || !val3) {
176
- result.append(work.substr(start, len));
177
- } else {
178
- bool nominative = has_nominative_article(work, start);
179
- std::u32string day_word;
180
-
181
- if (p1.size() == 4) {
182
- day_word = to_ordinal_int(static_cast<int32_t>(*val3), nominative ? U"e" : U"en");
183
- result.append(day_word + U" " + to_month(*val2) + U" " + to_year(*val1));
184
- } else {
185
- day_word = to_ordinal_int(static_cast<int32_t>(*val1), nominative ? U"e" : U"en");
186
- result.append(day_word + U" " + to_month(*val2) + U" " + to_year(*val3));
187
- }
188
- }
189
- } else {
190
- result.append(verbalize({work.substr(start, len), mode}));
191
- }
148
+ Case case_after(std::u32string_view word) {
149
+ std::u32string w(word);
150
+ return kDative.contains(w) ? Case::DATIVE :
151
+ kAccusative.contains(w) ? Case::ACCUSATIVE :
152
+ kGenitive.contains(w) ? Case::GENITIVE :
153
+ Case::NOMINATIVE;
154
+ }
192
155
 
193
- last_pos = start + len;
194
- i = start + len - 1;
195
- }
196
- }
156
+ bool capitalized(std::u32string_view word) {
157
+ return !word.empty() && unicode::isupper(word[0]);
158
+ }
197
159
 
198
- result.append(work.substr(last_pos));
199
- return result;
160
+ bool all_digits(std::u32string_view word) {
161
+ return !word.empty() && std::ranges::all_of(word, unicode::isdigit);
200
162
  }
201
163
 
202
- std::u32string Num2Word::to_cardinal_int(int32_t value) const {
203
- if (value < 0) {
204
- return U"minus " + to_cardinal_int(std::abs(value));
205
- }
164
+ // A number right after a capitalized noun is its label: Seite 1, Platz 1
165
+ bool labelled(const Context& context) {
166
+ auto head = words_of(context.head());
167
+ return !head.empty() && capitalized(head.back()) &&
168
+ !(head.size() == 1 || strings::contains(std::u32string_view(U".!?"), head[head.size() - 2].back()));
169
+ }
206
170
 
207
- if (value < 20) {
208
- return num2word::kCardinals.at(value);
171
+ // The ending of an ordinal from the words before it, and the noun it qualifies.
172
+ void resolve_ending(const Context& context, std::u32string_view noun, NumberReading& reading) {
173
+ std::vector<std::u32string> before;
174
+ for (auto word : words_of(context.head())) {
175
+ before.push_back(strings::to_lower(stripped(word)));
209
176
  }
210
177
 
211
- if (value < 100) {
212
- int32_t units = value % 10;
213
- int32_t tens = (value / 10) * 10;
214
- if (units == 0) {
215
- return num2word::kCardinals.at(tens);
178
+ // "in 2. und 3. Lesung", "vom 1. 5. bis 3. 5.": both take the ending of the first
179
+ static const std::array<std::u32string_view, 4> joining = {U"und", U"oder", U"bis", U"sowie"};
180
+ while (before.size() >= 2 && std::ranges::find(joining, before.back()) != joining.end() &&
181
+ all_digits(before[before.size() - 2])) {
182
+ before.resize(before.size() - 2);
183
+ while (!before.empty() && all_digits(before.back())) {
184
+ before.pop_back();
216
185
  }
217
- std::u32string unit_str = (units == 1) ? U"ein" : num2word::kCardinals.at(units);
218
- return unit_str + U"und" + num2word::kCardinals.at(tens);
219
186
  }
187
+ std::u32string w1 = before.empty() ? U"" : before.back();
188
+ std::u32string w2 = before.size() < 2 ? U"" : before[before.size() - 2];
189
+
190
+ reading.gender = gender_of(noun);
191
+ if (kWeak.contains(w1) || (w1 == U"der" && (kDative.contains(w2) || kGenitive.contains(w2)))) {
192
+ reading.declension = Declension::WEAK;
193
+ reading.grammatical_case = Case::DATIVE;
194
+ } else if (kWeakNominative.contains(w1)) {
195
+ reading.declension = Declension::WEAK;
196
+ reading.grammatical_case = Case::NOMINATIVE;
197
+ } else if (kMixed.contains(w1)) {
198
+ reading.declension = Declension::MIXED;
199
+ } else {
200
+ reading.declension = Declension::STRONG;
201
+ reading.grammatical_case = case_after(w1);
202
+ }
203
+ }
204
+ } // namespace
220
205
 
221
- for (auto it = num2word::kLargeCardinals.rbegin(); it != num2word::kLargeCardinals.rend(); ++it) {
222
- int64_t base = it->first;
223
- if (static_cast<int64_t>(value) >= base) {
224
- int32_t high = value / static_cast<int32_t>(base);
225
- int32_t low = value % static_cast<int32_t>(base);
226
-
227
- std::u32string head;
228
- if (high == 1) {
229
- head = (base >= 1000000LL) ? U"eine " : U"ein";
230
- } else {
231
- head = to_cardinal_int(high);
232
- if (base >= 1000000LL) {
233
- head += U" ";
234
- }
235
- }
236
-
237
- std::u32string scale = it->second;
238
- if (base >= 1000000LL && high > 1) {
239
- if (base == 1000000LL) scale = U"Millionen";
240
- else if (base == 1000000000LL) scale = U"Milliarden";
241
- }
206
+ Num2Word::Num2Word() : Num2WordLayer(kNotation, kJoiners) {
207
+ add_pattern(std::make_unique<DatePattern>(kDateFormat));
208
+ add_pattern(std::make_unique<PhonePattern>());
209
+ add_pattern(std::make_unique<DotOrdinalPattern>());
210
+ add_pattern(std::make_unique<SuffixPattern>(Kind::DECADE, kDecadeSuffixes, kDecadeFormat));
211
+ }
242
212
 
243
- std::u32string res = head + scale;
244
- if (low > 0) {
245
- if (base >= 1000000LL) res += U" ";
246
- res += to_cardinal_int(low);
213
+ // -----------------------
214
+ // ----- Resolution -----
215
+ // -----------------------
216
+
217
+ bool Num2Word::accept(const Match& match, const Context& context) const {
218
+ switch (match.kind) {
219
+ case Kind::DATE:
220
+ // "am 12. 3." is a date, "Platz 1. 2 Tore" is not
221
+ return match.text.find(U' ') == std::u32string_view::npos || kDateCues.contains(context.before());
222
+ case Kind::TIME:
223
+ if (match.numbers.size() == 2) {
224
+ bool decimal = match.separator == U'.' && match.suffix.empty();
225
+ return value(match.numbers[0]) <= 24 && value(match.numbers[1]) <= 59 && !decimal;
247
226
  }
248
- return res;
227
+ return true;
228
+ case Kind::ORDINAL: {
229
+ // "Platz 3. Danach", "Platz 1. 2 Tore": a sentence end, not an ordinal
230
+ static const std::unordered_set<std::u32string> inflecting = [] {
231
+ std::unordered_set<std::u32string> words = {U"und", U"oder", U"bis"};
232
+ for (const auto* set : {&kWeak, &kWeakNominative, &kMixed, &kDative, &kAccusative, &kGenitive}) {
233
+ words.insert(set->begin(), set->end());
234
+ }
235
+ return words;
236
+ }();
237
+ auto words = words_of(context.tail());
238
+ std::u32string_view next = words.empty() ? U"" : words[0];
239
+ bool month = std::ranges::find(kMonths, next) != kMonths.end();
240
+ bool sentence = capitalized(next) && !month && !inflecting.contains(context.before());
241
+ return !next.empty() && !unicode::isdigit(next[0]) && !sentence;
249
242
  }
243
+ default:
244
+ return true;
250
245
  }
251
-
252
- return conversions::utf8_to_u32(std::to_string(value));
253
246
  }
254
247
 
255
- std::u32string Num2Word::to_cardinal_float(float value, std::u32string_view repr) const {
256
- if (value < 0.0f) {
257
- return U"minus " + to_cardinal_float(std::abs(value), repr);
258
- }
248
+ NumberReading Num2Word::resolve(const Match& match, const Context& context) const {
249
+ NumberReading reading;
250
+
251
+ switch (match.kind) {
252
+ case Kind::DATE:
253
+ resolve_ending(context, U"Monat", reading);
254
+ return reading;
255
+
256
+ case Kind::ORDINAL: {
257
+ // The noun is the first capitalized word after it: der 3. Platz
258
+ std::u32string_view noun;
259
+ for (auto word : words_of(context.tail())) {
260
+ if (capitalized(word)) {
261
+ size_t end = word.find_last_not_of(U".,;:!?");
262
+ noun = word.substr(0, end == std::u32string_view::npos ? 0 : end + 1);
263
+ break;
264
+ }
265
+ }
266
+ resolve_ending(context, noun, reading);
267
+ return reading;
268
+ }
259
269
 
260
- std::string value_str = conversions::u32_to_utf8(repr);
261
- std::replace(value_str.begin(), value_str.end(), ',', '.');
270
+ case Kind::DECADE: {
271
+ std::u32string next = context.after();
272
+ reading.capitalized = next != U"Jahre" && next != U"Jahren" && next != U"Jahrgang";
273
+ return reading;
274
+ }
262
275
 
263
- auto rit = std::find_if(value_str.rbegin(), value_str.rend(), [](char c) { return c != '0'; });
264
- value_str = std::string(value_str.begin(), rit.base());
265
- if (!value_str.empty() && value_str.back() == '.') {
266
- value_str.pop_back();
276
+ default:
277
+ break;
267
278
  }
268
279
 
269
- size_t dot_pos = value_str.find('.');
270
- if (dot_pos == std::string::npos) {
271
- return to_cardinal_int(value_str.empty() ? 0 : std::stoi(value_str));
280
+ // "1" before a noun is said like an article, in the case of the word before it: mit einer Stimme
281
+ std::u32string next = context.after();
282
+ std::u32string noun = next;
283
+ if ((next == U"bis" || next == U"oder") && all_digits(context.after(2))) {
284
+ // "1 bis 2 Werktage": gendered by the plural noun
285
+ noun = context.after(3);
286
+ if (noun.ends_with(U"en")) {
287
+ noun.pop_back();
288
+ } else if (noun.ends_with(U'e')) {
289
+ noun.pop_back();
290
+ }
272
291
  }
292
+ reading.article = capitalized(noun) && noun != U"Quadrat" && (noun != next || !labelled(context));
293
+ reading.grammatical_case = case_after(context.before());
294
+ reading.gender = gender_of(noun);
295
+
296
+ // 1998 Abi gemacht, im Jahr 1945; but 1945 Einwohner, 1920 mal 1080
297
+ bool month = std::ranges::find(kMonths, next) != kMonths.end();
298
+ bool measure = next.ends_with(U'e') || next.ends_with(U'n') || next.ends_with(U"er") || next.ends_with(U's') ||
299
+ kMeasureWords.contains(next);
300
+ bool counted = capitalized(next) && measure && !month;
301
+ std::u32string previous = context.before();
302
+ bool times = next == U"mal" || previous == U"mal";
303
+ reading.year = !times && (kYearCues.contains(previous) || !counted);
304
+ return reading;
305
+ }
273
306
 
274
- std::string integer_part_str = value_str.substr(0, dot_pos);
275
- std::string fractional_part_str = value_str.substr(dot_pos + 1);
276
-
277
- int32_t integer_part = integer_part_str.empty() ? 0 : std::stoi(integer_part_str);
307
+ // --------------------
308
+ // ----- Readings -----
309
+ // --------------------
278
310
 
279
- std::u32string res = to_cardinal_int(integer_part) + U" Komma";
280
- for (char c : fractional_part_str) {
281
- if (isdigit(static_cast<unsigned char>(c))) {
282
- res += U" " + to_cardinal_int(c - '0');
283
- }
311
+ std::u32string Num2Word::read_number(const Number& number, const NumberReading& reading) const {
312
+ if (!number.fraction.empty()) {
313
+ std::u32string head = number.integer.empty() ? U"" : cardinal(value(number)) + U" ";
314
+ return head + U"Komma " + digits(number.fraction);
284
315
  }
285
316
 
286
- return res;
317
+ auto n = value_of(number.integer);
318
+ if (!n || spoken_digits(number, 5)) {
319
+ return digits(number.integer);
320
+ }
321
+ if (*n == 1 && reading.article) {
322
+ return article(reading.grammatical_case, reading.gender);
323
+ }
324
+ if (number.integer.size() == 4 && !number.grouped && reading.year) {
325
+ return year(*n);
326
+ }
327
+ return cardinal(*n);
287
328
  }
288
329
 
289
- std::u32string Num2Word::to_ordinal_int(int32_t value, std::u32string_view suffix) const {
290
- if (value < 0) {
291
- return U"minus " + to_ordinal_int(std::abs(value), suffix);
330
+ std::u32string Num2Word::read_code_digits(std::u32string_view text) const {
331
+ auto n = value_of(text);
332
+ if ((text.size() > 1 && text[0] == U'0') || text.size() > 4 || !n) {
333
+ return digits(text);
292
334
  }
335
+ return year(*n);
336
+ }
337
+
338
+ std::u32string Num2Word::read_date(const Match& match, const NumberReading& reading) const {
339
+ std::u32string words =
340
+ ordinal(value(match.numbers[0]), ending(reading)) + U" " + kMonths[value(match.numbers[1]) - 1];
341
+ return match.numbers.size() < 3 ? words : words + U" " + year(value(match.numbers[2]));
342
+ }
293
343
 
294
- std::u32string stem;
295
- if (value == 1) stem = U"erst";
296
- else if (value == 3) stem = U"dritt";
297
- else if (value == 7) stem = U"siebt";
298
- else if (value == 8) stem = U"acht";
299
- else if (value < 20) stem = to_cardinal_int(value) + U"t";
300
- else stem = to_cardinal_int(value) + U"st";
301
-
302
- std::u32string ending = U"e";
303
- if (!suffix.empty()) {
304
- char32_t last = utils::unicode::tolower(suffix.back());
305
- if (last == U'n') ending = U"en";
306
- else if (last == U'r') ending = U"er";
307
- else if (last == U's') ending = U"es";
308
- else if (last == U'm') ending = U"em";
344
+ std::u32string Num2Word::read_phone(const Match& match, const NumberReading& reading) const {
345
+ std::u32string all;
346
+ for (const auto& group : match.numbers) {
347
+ all += group.integer;
309
348
  }
349
+ return digits(all);
350
+ }
310
351
 
311
- return stem + ending;
352
+ std::u32string Num2Word::read_fraction(const Match& match, const NumberReading& reading) const {
353
+ uint64_t a = value(match.numbers[0]), b = value(match.numbers[1]);
354
+ auto it = kFractions.find({a, b});
355
+ return it != kFractions.end() ? it->second : cardinal(a) + U" durch " + cardinal(b);
312
356
  }
313
357
 
314
- std::u32string Num2Word::to_currency(char32_t currency, std::variant<int32_t, float> number) const {
315
- if (!num2word::kCurrencies.contains(currency)) {
316
- return std::u32string(1, currency);
358
+ std::u32string Num2Word::read_time(const Match& match, const NumberReading& reading) const {
359
+ std::u32string words = stem(value(match.numbers[0])) + U" Uhr";
360
+ if (match.numbers.size() == 2 && value(match.numbers[1]) > 0) {
361
+ words += U" " + cardinal(value(match.numbers[1]));
317
362
  }
318
- return num2word::kCurrencies.at(currency);
363
+ return words;
319
364
  }
320
365
 
321
- std::u32string Num2Word::to_month(uint32_t month) const {
322
- if (month >= 1 && month <= 12) {
323
- return num2word::kMonths[month];
324
- }
325
- return U"";
366
+ std::u32string Num2Word::read_ordinal(const Match& match, const NumberReading& reading) const {
367
+ return ordinal(value(match.numbers[0]), ending(reading));
326
368
  }
327
369
 
328
- std::u32string Num2Word::to_year(uint32_t year) const {
329
- if (year >= 1100 && year < 2000) {
330
- int32_t hundreds = year / 100;
331
- int32_t remainder = year % 100;
332
- std::u32string res = to_cardinal_int(hundreds) + U"hundert";
333
- if (remainder > 0) {
334
- res += to_cardinal_int(remainder);
335
- }
336
- return res;
370
+ std::u32string Num2Word::read_decade(const Match& match, const NumberReading& reading) const {
371
+ // 90er, 90ern: neunziger, neunzigern; 1990er: neunzehnhundertneunziger
372
+ const auto& digits = match.numbers[0].integer;
373
+ std::u32string number = digits.size() > 1 && digits[0] == U'0' ? U"null" + cardinal(value(match.numbers[0])) :
374
+ year(value(match.numbers[0]));
375
+ std::u32string words = number + std::u32string(match.suffix);
376
+ if (reading.capitalized) {
377
+ words[0] = unicode::toupper(words[0]);
337
378
  }
338
- return to_cardinal_int(static_cast<int32_t>(year));
379
+ return words;
339
380
  }
340
381
 
341
- bool Num2Word::is_ordinal_suffix(std::u32string_view suffix) const {
342
- return num2word::kOrdinalSuffixes.contains(std::u32string(suffix));
382
+ std::u32string Num2Word::read_compound(const Match& match, const NumberReading& reading) const {
383
+ // 30-jährige: dreißigjährige; 4-Zimmer-Wohnung: Vier-Zimmer-Wohnung
384
+ const Number& number = match.numbers[0];
385
+ std::u32string words =
386
+ number.fraction.empty() && !number.grouped ? stem(value(number)) : read_number(number, reading);
387
+ if (capitalized(match.suffix)) {
388
+ words[0] = unicode::toupper(words[0]);
389
+ return words + U"-" + std::u32string(match.suffix);
390
+ }
391
+ return words + std::u32string(match.suffix);
343
392
  }
344
393
 
345
- std::u32string Num2Word::to_fraction(int32_t numerator, int32_t denominator) const {
346
- std::u32string num_word = (numerator == 1) ? U"ein" : to_cardinal_int(numerator);
347
- std::u32string den_word;
348
- if (denominator == 2) {
349
- den_word = U"halb";
350
- } else if (denominator == 3) {
351
- den_word = U"drittel";
352
- } else if (denominator == 4) {
353
- den_word = U"viertel";
354
- } else if (denominator < 20) {
355
- den_word = to_cardinal_int(denominator) + U"tel";
356
- } else {
357
- den_word = to_cardinal_int(denominator) + U"stel";
394
+ std::u32string Num2Word::read_money(const Number& number, const Match& match, const NumberReading& reading) const {
395
+ const std::u32string& noun = kCurrencies.at(std::u32string(match.unit));
396
+ std::u32string one = article(reading.grammatical_case, gender_of(noun));
397
+ if (!match.scale.empty()) {
398
+ return read_scale(number, match, reading) + U" " + noun;
358
399
  }
359
400
 
360
- if (!den_word.empty()) {
361
- den_word[0] = utils::unicode::toupper(den_word[0]);
401
+ // A price: drei Euro fünfzig, neunundneunzig Cent
402
+ if (number.fraction.size() == 2) {
403
+ uint64_t cents = value_of(number.fraction).value_or(0);
404
+ if (value(number) == 0) {
405
+ return cardinal(cents) + U" Cent";
406
+ }
407
+ Number whole{.integer = number.integer, .grouped = number.grouped};
408
+ std::u32string words = number.integer == U"1" ? one : read_number(whole, reading);
409
+ return words + U" " + noun + U" " + cardinal(cents);
362
410
  }
363
- return num_word + U" " + den_word;
364
- }
365
411
 
366
- std::u32string Num2Word::to_day(uint32_t day) const {
367
- return to_ordinal_int(static_cast<int32_t>(day));
412
+ bool single = number.integer == U"1" && number.fraction.empty();
413
+ return (single ? one : read_number(number, reading)) + U" " + noun;
368
414
  }
369
415
 
370
- std::u32string Num2Word::verbalize(const StringifiedNumber& number) const {
371
- if (number.conversionMode != Mode::CURRENCY) {
372
- return Num2WordLayer::verbalize(number);
416
+ std::u32string Num2Word::read_scale(const Number& number, const Match& match, const NumberReading& reading) const {
417
+ const Forms& scale = kScales.at(std::u32string(match.scale));
418
+ if (scale.many == U"tausend") {
419
+ return read_number(number, reading) + U"tausend";
373
420
  }
421
+ bool single = number.integer == U"1" && number.fraction.empty();
422
+ return single ? U"eine " + scale.one : read_number(number, reading) + U" " + scale.many;
423
+ }
374
424
 
375
- char32_t currency = number.text.back();
376
- std::u32string_view num_part = number.text.substr(0, number.text.size() - 1);
425
+ std::u32string Num2Word::read_percent(const Number& number, const Match& match, const NumberReading& reading) const {
426
+ std::u32string words = read_number(number, reading);
427
+ // 8%ige: achtprozentige
428
+ return match.suffix.empty() ? words + U" Prozent" : words + U"prozent" + std::u32string(match.suffix);
429
+ }
377
430
 
378
- if (num_part.find(U'.') != std::u32string_view::npos) {
379
- auto val = as_float(num_part);
380
- if (!val) return U"";
381
- bool singular = std::abs(*val - 1.0F) < 1e-6F;
382
- std::u32string amount = singular ? U"ein" : to_cardinal_float(*val, num_part);
383
- return amount + U" " + to_currency(currency, *val);
431
+ std::u32string Num2Word::read_unit(const Number& number, const Match& match, const NumberReading& reading) const {
432
+ const Forms& unit = kUnits.at(std::u32string(match.unit));
433
+ if (number.integer == U"1" && number.fraction.empty()) {
434
+ return article(reading.grammatical_case, gender_of(unit.one)) + U" " + unit.one;
384
435
  }
385
-
386
- auto val = as_int(num_part);
387
- if (!val) return U"";
388
- bool singular = (*val == 1);
389
- std::u32string amount = singular ? U"ein" : to_cardinal_int(*val);
390
- return amount + U" " + to_currency(currency, *val);
436
+ return read_number(number, reading) + U" " + unit.many;
391
437
  }
392
438
 
393
439
  } // namespace phonemis::de