react-native-executorch 0.10.5 → 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 (251) hide show
  1. package/README.md +10 -1
  2. package/android/build.gradle.kts +4 -3
  3. package/ios/RnExecutorch.mm +15 -17
  4. package/lib/module/fetcher/fetcher.js +35 -122
  5. package/lib/module/fetcher/fetcher.js.map +1 -1
  6. package/lib/module/fetcher/telemetry.js +1 -1
  7. package/lib/module/index.js +12 -13
  8. package/lib/module/index.js.map +1 -1
  9. package/lib/module/models.js +4 -2
  10. package/lib/module/models.js.map +1 -1
  11. package/lib/typescript/src/fetcher/fetcher.d.ts +3 -7
  12. package/lib/typescript/src/fetcher/fetcher.d.ts.map +1 -1
  13. package/lib/typescript/src/models.d.ts.map +1 -1
  14. package/package.json +9 -7
  15. package/react-native-executorch.podspec +6 -2
  16. package/src/fetcher/fetcher.ts +38 -131
  17. package/src/fetcher/telemetry.ts +1 -1
  18. package/src/models.ts +6 -1
  19. package/third-party/common/phonemis/CMakeLists.txt +70 -14
  20. package/third-party/common/phonemis/README.md +183 -33
  21. package/third-party/common/phonemis/THIRD_PARTY_NOTICES.md +57 -0
  22. package/third-party/common/phonemis/knowledge/code_style.md +642 -0
  23. package/third-party/common/phonemis/licenses/Unicode-3.0.txt +39 -0
  24. package/third-party/common/phonemis/licenses/misaki-Apache-2.0.txt +201 -0
  25. package/third-party/common/phonemis/licenses/nlohmann-json-MIT.txt +21 -0
  26. package/third-party/common/phonemis/licenses/xsimd-BSD-3-Clause.txt +29 -0
  27. package/third-party/common/phonemis/src/phonemis/base/config.h +6 -0
  28. package/third-party/common/phonemis/src/phonemis/base/ipipeline.cpp +75 -0
  29. package/third-party/common/phonemis/src/phonemis/base/ipipeline.h +21 -0
  30. package/third-party/common/phonemis/src/phonemis/base/phonemizer/constants.h +2 -5
  31. package/third-party/common/phonemis/src/phonemis/base/phonemizer/lexicon_phonemizer.cpp +3 -4
  32. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.cpp +17 -8
  33. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.h +4 -0
  34. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.cpp +21 -6
  35. package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.h +13 -4
  36. package/third-party/common/phonemis/src/phonemis/base/pipeline.cpp +8 -0
  37. package/third-party/common/phonemis/src/phonemis/base/pipeline.h +19 -0
  38. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.cpp +37 -0
  39. package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.h +45 -0
  40. package/third-party/common/phonemis/src/phonemis/base/processor/common/constants.h +10 -0
  41. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.cpp +105 -0
  42. package/third-party/common/phonemis/src/phonemis/base/processor/common/context.h +49 -0
  43. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.cpp +173 -0
  44. package/third-party/common/phonemis/src/phonemis/base/processor/common/document.h +67 -0
  45. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.cpp +75 -0
  46. package/third-party/common/phonemis/src/phonemis/base/processor/common/text.h +60 -0
  47. package/third-party/common/phonemis/src/phonemis/base/processor/common/types.h +18 -0
  48. package/third-party/common/phonemis/src/phonemis/base/processor/config.h +53 -0
  49. package/third-party/common/phonemis/src/phonemis/base/processor/layer.h +9 -7
  50. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/constants.h +20 -0
  51. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.cpp +89 -0
  52. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.h +35 -0
  53. package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/types.h +16 -0
  54. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/kind.h +40 -0
  55. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/layer.h +382 -0
  56. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/notation.h +30 -0
  57. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.cpp +51 -0
  58. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.h +31 -0
  59. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern.h +30 -0
  60. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.cpp +17 -0
  61. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.h +31 -0
  62. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.cpp +811 -0
  63. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.h +285 -0
  64. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.cpp +64 -0
  65. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.h +23 -0
  66. package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/types.h +94 -0
  67. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sanitizer/layer.cpp +19 -0
  68. package/third-party/common/phonemis/src/phonemis/base/processor/{sanitizer_layer.h → layers/sanitizer/layer.h} +8 -8
  69. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.cpp +65 -0
  70. package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.h +29 -0
  71. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.cpp +170 -0
  72. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.h +40 -0
  73. package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/types.h +25 -0
  74. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.cpp +47 -0
  75. package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.h +19 -0
  76. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.cpp +60 -0
  77. package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.h +45 -0
  78. package/third-party/common/phonemis/src/phonemis/base/processor/processor.cpp +6 -7
  79. package/third-party/common/phonemis/src/phonemis/base/processor/processor.h +14 -10
  80. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.cpp +89 -52
  81. package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.h +16 -9
  82. package/third-party/common/phonemis/src/phonemis/base/tokenizer/tokenizer.cpp +13 -12
  83. package/third-party/common/phonemis/src/phonemis/lang/de/constants.h +183 -19
  84. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.cpp +355 -309
  85. package/third-party/common/phonemis/src/phonemis/lang/de/num2word.h +42 -17
  86. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.cpp +56 -0
  87. package/third-party/common/phonemis/src/phonemis/lang/de/patterns.h +15 -0
  88. package/third-party/common/phonemis/src/phonemis/lang/de/pipeline.h +3 -3
  89. package/third-party/common/phonemis/src/phonemis/lang/en/constants.h +181 -30
  90. package/third-party/common/phonemis/src/phonemis/lang/en/hmm_tagger.cpp +5 -7
  91. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.cpp +232 -135
  92. package/third-party/common/phonemis/src/phonemis/lang/en/num2word.h +41 -16
  93. package/third-party/common/phonemis/src/phonemis/lang/en/pipeline.h +3 -10
  94. package/third-party/common/phonemis/src/phonemis/lang/es/constants.h +182 -60
  95. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.cpp +247 -212
  96. package/third-party/common/phonemis/src/phonemis/lang/es/num2word.h +38 -18
  97. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.cpp +50 -0
  98. package/third-party/common/phonemis/src/phonemis/lang/es/patterns.h +15 -0
  99. package/third-party/common/phonemis/src/phonemis/lang/es/pipeline.h +3 -3
  100. package/third-party/common/phonemis/src/phonemis/lang/fr/constants.h +152 -26
  101. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.cpp +252 -179
  102. package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.h +38 -15
  103. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.cpp +83 -0
  104. package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.h +15 -0
  105. package/third-party/common/phonemis/src/phonemis/lang/fr/pipeline.h +3 -3
  106. package/third-party/common/phonemis/src/phonemis/lang/hi/constants.h +62 -10
  107. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.cpp +74 -123
  108. package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.h +27 -16
  109. package/third-party/common/phonemis/src/phonemis/lang/hi/pipeline.h +5 -3
  110. package/third-party/common/phonemis/src/phonemis/lang/it/constants.h +122 -42
  111. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.cpp +200 -207
  112. package/third-party/common/phonemis/src/phonemis/lang/it/num2word.h +30 -18
  113. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.cpp +25 -0
  114. package/third-party/common/phonemis/src/phonemis/lang/it/patterns.h +15 -0
  115. package/third-party/common/phonemis/src/phonemis/lang/it/pipeline.h +3 -3
  116. package/third-party/common/phonemis/src/phonemis/lang/pl/constants.h +346 -77
  117. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.cpp +631 -246
  118. package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.h +47 -15
  119. package/third-party/common/phonemis/src/phonemis/lang/pl/pipeline.h +6 -6
  120. package/third-party/common/phonemis/src/phonemis/lang/pt/constants.h +201 -0
  121. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.cpp +365 -0
  122. package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.h +53 -0
  123. package/third-party/common/phonemis/src/phonemis/lang/pt/pipeline.h +4 -2
  124. package/third-party/common/phonemis/src/phonemis/main.cpp +42 -11
  125. package/third-party/common/phonemis/src/phonemis/protophone/meta.h +24 -0
  126. package/third-party/common/phonemis/src/phonemis/protophone/numeric.h +26 -0
  127. package/third-party/common/phonemis/src/phonemis/protophone/protophone.cpp +525 -0
  128. package/third-party/common/phonemis/src/phonemis/protophone/protophone.h +80 -0
  129. package/third-party/common/phonemis/src/phonemis/protophone/tensor.h +76 -0
  130. package/third-party/common/phonemis/src/phonemis/protophone/tensor_utils.h +89 -0
  131. package/third-party/common/phonemis/src/phonemis/protophone/tensor_view.h +125 -0
  132. package/third-party/common/phonemis/src/phonemis/protophone/types.h +43 -0
  133. package/third-party/common/phonemis/src/phonemis/utils/strings.h +20 -14
  134. package/third-party/common/phonemis/src/phonemis/utils/unicode.h +15 -1
  135. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_arithmetic.hpp +267 -0
  136. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_bit.hpp +232 -0
  137. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_cast.hpp +43 -0
  138. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_complex.hpp +112 -0
  139. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_details.hpp +386 -0
  140. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_logical.hpp +240 -0
  141. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_math.hpp +2601 -0
  142. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_memory.hpp +1006 -0
  143. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_rounding.hpp +72 -0
  144. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_swizzle.hpp +260 -0
  145. package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_trigo.hpp +996 -0
  146. package/third-party/common/phonemis/src/third-party/xsimd/arch/utils/shifts.hpp +82 -0
  147. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx.hpp +2111 -0
  148. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2.hpp +1591 -0
  149. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2_128.hpp +170 -0
  150. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512bw.hpp +724 -0
  151. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512cd.hpp +28 -0
  152. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512dq.hpp +270 -0
  153. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512er.hpp +17 -0
  154. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512f.hpp +2919 -0
  155. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512ifma.hpp +17 -0
  156. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512pf.hpp +17 -0
  157. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi.hpp +76 -0
  158. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi2.hpp +130 -0
  159. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512bw.hpp +17 -0
  160. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512vbmi2.hpp +17 -0
  161. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx_128.hpp +164 -0
  162. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avxvnni.hpp +17 -0
  163. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common.hpp +26 -0
  164. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common_fwd.hpp +127 -0
  165. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_constants.hpp +393 -0
  166. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_emulated.hpp +787 -0
  167. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx.hpp +93 -0
  168. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx2.hpp +46 -0
  169. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_sse.hpp +97 -0
  170. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma4.hpp +92 -0
  171. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_i8mm_neon64.hpp +17 -0
  172. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_isa.hpp +148 -0
  173. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon.hpp +3580 -0
  174. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon64.hpp +1614 -0
  175. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_rvv.hpp +1515 -0
  176. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_scalar.hpp +1210 -0
  177. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse2.hpp +2333 -0
  178. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse3.hpp +66 -0
  179. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_1.hpp +510 -0
  180. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_2.hpp +44 -0
  181. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_ssse3.hpp +186 -0
  182. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sve.hpp +1186 -0
  183. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vsx.hpp +947 -0
  184. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vxe.hpp +787 -0
  185. package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_wasm.hpp +1819 -0
  186. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_arch.hpp +242 -0
  187. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_config.hpp +633 -0
  188. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features.hpp +50 -0
  189. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_arm.hpp +132 -0
  190. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_ppc.hpp +54 -0
  191. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_riscv.hpp +95 -0
  192. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_s390x.hpp +56 -0
  193. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_x86.hpp +1121 -0
  194. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpuid.hpp +144 -0
  195. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_getauxval.hpp +159 -0
  196. package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_macros.hpp +78 -0
  197. package/third-party/common/phonemis/src/third-party/xsimd/math/xsimd_rem_pio2.hpp +707 -0
  198. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_aligned_allocator.hpp +349 -0
  199. package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_alignment.hpp +102 -0
  200. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_all_registers.hpp +57 -0
  201. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_api.hpp +3106 -0
  202. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx2_register.hpp +57 -0
  203. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512bw_register.hpp +51 -0
  204. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512cd_register.hpp +51 -0
  205. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512dq_register.hpp +51 -0
  206. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512er_register.hpp +51 -0
  207. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512f_register.hpp +77 -0
  208. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512ifma_register.hpp +51 -0
  209. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512pf_register.hpp +51 -0
  210. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi2_register.hpp +51 -0
  211. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi_register.hpp +51 -0
  212. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512bw_register.hpp +54 -0
  213. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512vbmi2_register.hpp +53 -0
  214. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx_register.hpp +79 -0
  215. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avxvnni_register.hpp +44 -0
  216. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch.hpp +1666 -0
  217. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_constant.hpp +572 -0
  218. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_fwd.hpp +41 -0
  219. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_common_arch.hpp +49 -0
  220. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_emulated_register.hpp +80 -0
  221. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx2_register.hpp +50 -0
  222. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx_register.hpp +50 -0
  223. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_sse_register.hpp +50 -0
  224. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma4_register.hpp +50 -0
  225. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_i8mm_neon64_register.hpp +55 -0
  226. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon64_register.hpp +55 -0
  227. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon_register.hpp +130 -0
  228. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_register.hpp +96 -0
  229. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_rvv_register.hpp +491 -0
  230. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse2_register.hpp +59 -0
  231. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse3_register.hpp +49 -0
  232. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_1_register.hpp +48 -0
  233. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_2_register.hpp +48 -0
  234. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_ssse3_register.hpp +48 -0
  235. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sve_register.hpp +216 -0
  236. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_traits.hpp +409 -0
  237. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_utils.hpp +462 -0
  238. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vsx_register.hpp +84 -0
  239. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vxe_register.hpp +86 -0
  240. package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_wasm_register.hpp +59 -0
  241. package/third-party/common/phonemis/src/third-party/xsimd/utils/bits.hpp +122 -0
  242. package/third-party/common/phonemis/src/third-party/xsimd/utils/xsimd_type_traits.hpp +145 -0
  243. package/third-party/common/phonemis/src/third-party/xsimd/xsimd.hpp +43 -0
  244. package/third-party/common/phonemis/src/phonemis/base/processor/constants.h +0 -11
  245. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/config.h +0 -16
  246. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.cpp +0 -271
  247. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.h +0 -45
  248. package/third-party/common/phonemis/src/phonemis/base/processor/num2word/types.h +0 -29
  249. package/third-party/common/phonemis/src/phonemis/base/processor/sanitizer_layer.cpp +0 -22
  250. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.cpp +0 -40
  251. package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.h +0 -22
@@ -1,279 +1,314 @@
1
- #include "num2word.h"
2
1
  #include "constants.h"
3
- #include <phonemis/utils/conversions.h>
4
- #include <algorithm>
5
- #include <cmath>
6
- #include <cstdlib>
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>
8
+ #include <phonemis/utils/unicode.h>
7
9
 
8
10
  namespace phonemis::es {
9
11
 
10
- using namespace constants;
11
- using namespace phonemis::utils;
12
+ using namespace constants::num2word;
13
+ using namespace processor;
14
+ using namespace processor::num2word;
15
+ using namespace utils;
12
16
 
13
17
  namespace {
18
+ uint64_t value(const Number& number) {
19
+ return value_of(number.integer).value_or(0);
20
+ }
14
21
 
15
- // Apocopates a trailing cardinal "uno" to "un" (and "veintiuno" to "veintiún")
16
- // when the cardinal precedes a masculine noun — required for Spanish currency
17
- // amounts and fraction numerators (e.g. "un dólar", "un medio").
18
- std::u32string apocopate(std::u32string word) {
19
- constexpr std::u32string_view kVeintiuno = U"veintiuno";
20
- if (word.size() >= kVeintiuno.size() &&
21
- std::u32string_view(word).substr(word.size() - kVeintiuno.size()) == kVeintiuno) {
22
- word.replace(word.size() - kVeintiuno.size(), kVeintiuno.size(), U"veintiún");
23
- return word;
24
- }
25
- constexpr std::u32string_view kUno = U"uno";
26
- if (word.size() >= kUno.size() &&
27
- std::u32string_view(word).substr(word.size() - kUno.size()) == kUno) {
28
- // Only apocopate when "uno" is a standalone token (the whole word or
29
- // preceded by a word boundary). This guards against accidentally trimming
30
- // words that happen to end in the three letters "uno".
31
- size_t pre = word.size() - kUno.size();
32
- if (pre == 0 || word[pre - 1] == U' ' || word[pre - 1] == U'-') {
33
- word.replace(pre, kUno.size(), U"un");
34
- }
35
- }
36
- return word;
22
+ // The number "1" as written, which counts a singular noun
23
+ bool is_one(const Number& number) {
24
+ return number.integer == U"1" && number.fraction.empty();
37
25
  }
38
26
 
39
- } // namespace
27
+ // ------------------------
28
+ // ----- Number words -----
29
+ // ------------------------
40
30
 
41
- std::u32string Num2Word::to_cardinal_int(int32_t value) const {
42
- if (value < 0) {
43
- return U"menos " + to_cardinal_int(std::abs(value));
31
+ std::u32string below_hundred(uint64_t n, One one) {
32
+ std::u32string words(n < 30 ? kOnes[n] : kTens[n / 10]);
33
+ if (n >= 30 && n % 10) {
34
+ words += U" y " + std::u32string(kOnes[n % 10]);
44
35
  }
45
36
 
46
- if (auto it = num2word::kCardinals.find(value); it != num2word::kCardinals.end()) {
47
- return it->second;
37
+ // veintiún años, treinta y una personas
38
+ if (words.ends_with(U"uno") && one != One::UNO) {
39
+ words.resize(words.size() - 3);
40
+ words += one == One::UNA ? U"una" : (words == U"veinti" ? U"ún" : U"un");
48
41
  }
42
+ return words;
43
+ }
49
44
 
50
- if (value < 100) {
51
- // 31-99 (non-round tens): Spanish writes them as "<tens> y <units>".
52
- int32_t tens = (value / 10) * 10;
53
- int32_t units = value % 10;
54
- return num2word::kCardinals.at(tens) + U" y " + num2word::kCardinals.at(units);
45
+ std::u32string below_thousand(uint64_t n, One one) {
46
+ uint64_t h = n / 100, r = n % 100;
47
+ if (h == 0) {
48
+ return below_hundred(r, one);
49
+ }
50
+ if (n == 100) {
51
+ return U"cien";
55
52
  }
56
53
 
57
- if (value < 1000) {
58
- // 100 is "cien" standalone but "ciento" when followed by a smaller part
59
- // (e.g. 123 = "ciento veintitrés"). 200-900 keep their base form.
60
- int32_t hundreds = (value / 100) * 100;
61
- int32_t rest = value % 100;
62
- std::u32string head = (hundreds == 100) ? U"ciento" : num2word::kCardinals.at(hundreds);
63
- return (rest == 0) ? num2word::kCardinals.at(hundreds)
64
- : head + U" " + to_cardinal_int(rest);
54
+ // doscientas personas
55
+ std::u32string head(kHundreds[h]);
56
+ if (one == One::UNA && h > 1) {
57
+ head.replace(head.size() - 2, 2, U"as");
65
58
  }
59
+ return head + (r ? U" " + below_hundred(r, one) : U"");
60
+ }
66
61
 
67
- // Large-scale decomposition (mil, millón, billón) in descending order.
68
- for (auto it = num2word::kLargeCardinals.rbegin(); it != num2word::kLargeCardinals.rend(); ++it) {
69
- int64_t base = it->first;
70
- if (static_cast<int64_t>(value) >= base) {
71
- int32_t high = value / static_cast<int32_t>(base);
72
- int32_t low = value % static_cast<int32_t>(base);
73
-
74
- // "mil" drops the leading "un" when used as a multiplier of 1 (1000 =
75
- // "mil"), but "millón"/"billón" keep it ("un millón", "un billón").
76
- std::u32string head;
77
- if (high == 1 && base == 1000LL) {
78
- head = U"";
79
- } else if (high == 1) {
80
- head = U"un ";
81
- } else {
82
- head = to_cardinal_int(high) + U" ";
83
- }
62
+ // A cardinal, ending with the given form of "uno": doscientas mil personas, veintiún años
63
+ std::u32string cardinal(uint64_t n, One one = One::UNO) {
64
+ if (n < 1000) {
65
+ return below_thousand(n, one);
66
+ }
67
+ if (n < 1000000) {
68
+ uint64_t t = n / 1000, r = n % 1000;
69
+ std::u32string head = t == 1 ? U"mil" : below_thousand(t, one == One::UNA ? One::UNA : One::UN) + U" mil";
70
+ return head + (r ? U" " + below_thousand(r, one) : U"");
71
+ }
84
72
 
85
- std::u32string scale = (high > 1) ? num2word::kLargeCardinalsPlural.at(base)
86
- : it->second;
73
+ bool billions = n >= 1000000000000ULL;
74
+ uint64_t scale = billions ? 1000000000000ULL : 1000000ULL, q = n / scale, r = n % scale;
75
+ std::u32string head = q == 1 ? (billions ? U"un billón" : U"un millón") :
76
+ cardinal(q, One::UN) + (billions ? U" billones" : U" millones");
77
+ return head + (r ? U" " + cardinal(r, one) : U"");
78
+ }
87
79
 
88
- std::u32string res = head + scale;
89
- if (low > 0) {
90
- res += U" " + to_cardinal_int(low);
91
- }
92
- return res;
80
+ // centésima trigésima séptima
81
+ std::u32string ordinal(uint64_t n, bool feminine) {
82
+ std::vector<std::u32string> words;
83
+ for (auto [scale, stems] :
84
+ {std::pair{100, &kOrdinalHundreds}, std::pair{10, &kOrdinalTens}, std::pair{1, &kOrdinalOnes}}) {
85
+ if (uint64_t digit = n / scale % 10) {
86
+ words.push_back(std::u32string((*stems)[digit]) + (feminine ? U"a" : U"o"));
93
87
  }
94
88
  }
95
-
96
- return conversions::utf8_to_u32(std::to_string(value));
89
+ return join(words);
97
90
  }
98
91
 
99
- std::u32string Num2Word::to_cardinal_float(float value, std::u32string_view repr) const {
100
- if (value < 0.0f) {
101
- return U"menos " + to_cardinal_float(std::abs(value), repr);
92
+ std::u32string digits(std::u32string_view text) {
93
+ std::vector<std::u32string> words;
94
+ for (char32_t c : text) {
95
+ if (unicode::isdigit(c)) {
96
+ words.emplace_back(kOnes[c - U'0']);
97
+ }
102
98
  }
99
+ return join(words);
100
+ }
103
101
 
104
- // The base transform normalizes the decimal separator to '.', but accept ','
105
- // too when this method is invoked directly with a raw representation.
106
- std::string value_str = conversions::u32_to_utf8(repr);
107
- std::replace(value_str.begin(), value_str.end(), ',', '.');
108
-
109
- // Trim trailing zeros and any dangling decimal point.
110
- auto rit = std::find_if(value_str.rbegin(), value_str.rend(),
111
- [](char c) { return c != '0'; });
112
- value_str = std::string(value_str.begin(), rit.base());
113
- if (!value_str.empty() && value_str.back() == '.') {
114
- value_str.pop_back();
102
+ // -------------------
103
+ // ----- Context -----
104
+ // -------------------
105
+
106
+ bool feminine(std::u32string_view noun) {
107
+ std::u32string word = strings::to_lower(noun);
108
+ std::u32string singular = word;
109
+ if (word.ends_with(U"iones")) {
110
+ singular = word.substr(0, word.size() - 5) + U"ión";
111
+ } else if (word.ends_with(U"as") || word.ends_with(U"es")) {
112
+ singular.pop_back();
115
113
  }
116
114
 
117
- size_t dot_pos = value_str.find('.');
118
- if (dot_pos == std::string::npos) {
119
- return to_cardinal_int(value_str.empty() ? 0 : std::stoi(value_str));
115
+ if (kFeminineNouns.contains(word) || kFeminineNouns.contains(singular)) {
116
+ return true;
120
117
  }
118
+ bool feminine_ending = std::ranges::any_of(kFeminineEndings, [&](const auto& e) { return singular.ends_with(e); });
119
+ return !kMasculineInA.contains(singular) && feminine_ending;
120
+ }
121
121
 
122
- std::string integer_part_str = value_str.substr(0, dot_pos);
123
- std::string fractional_part_str = value_str.substr(dot_pos + 1);
124
- int32_t integer_part = integer_part_str.empty() ? 0 : std::stoi(integer_part_str);
125
-
126
- // Leading zeros in the fractional part are spoken as "cero" words; the
127
- // remaining digits are verbalized as a single cardinal number (e.g. 0,05 ->
128
- // "cero coma cero cinco", 123,45 -> "... coma cuarenta y cinco").
129
- std::u32string frac_words;
130
- size_t pos = 0;
131
- while (pos < fractional_part_str.size() && fractional_part_str[pos] == '0') {
132
- if (!frac_words.empty()) frac_words += U" ";
133
- frac_words += U"cero";
134
- pos++;
122
+ // The form of "uno" from the noun after a number: veintiún años, veintiuna personas; a la 1
123
+ One one_of(const Context& context) {
124
+ std::u32string word = context.after();
125
+ std::u32string previous = context.before();
126
+ if (previous == U"la" || previous == U"las") {
127
+ return One::UNA;
135
128
  }
136
- if (pos < fractional_part_str.size()) {
137
- if (!frac_words.empty()) frac_words += U" ";
138
- frac_words += to_cardinal_int(std::stoi(fractional_part_str.substr(pos)));
129
+ if (word.empty() || !unicode::isalpha(word[0]) || kStopWords.contains(strings::to_lower(word))) {
130
+ return One::UNO;
139
131
  }
132
+ return feminine(word) ? One::UNA : One::UN;
133
+ }
140
134
 
141
- return to_cardinal_int(integer_part) + U" coma " + frac_words;
135
+ // A lowercase noun follows: 10k seguidores
136
+ bool counted(const Context& context) {
137
+ std::u32string word = context.after();
138
+ bool lowercase_word = word.size() > 2 && std::ranges::all_of(word, [](char32_t c) { return unicode::islower(c); });
139
+ return lowercase_word && !kStopWords.contains(word);
142
140
  }
141
+ } // namespace
143
142
 
144
- std::u32string Num2Word::to_ordinal_int(int32_t value, std::u32string_view suffix) const {
145
- // The suffix disambiguates gender/number/apocope; the default (no suffix,
146
- // e.g. from a "1." token) is masculine singular full form ("primero").
147
- bool feminine = (suffix == U"ª" || suffix == U"ªs");
148
- bool apocope = (suffix == U"er" || suffix == U"ers");
149
- bool plural = (suffix == U"ers" || suffix == U"ªs" || suffix == U"ºs");
150
-
151
- auto inflect = [&](std::u32string word) {
152
- if (apocope) {
153
- // Only "primero"/"tercero" have distinct apocopated forms; for other
154
- // ordinals the "er" suffix is atypical but we fall back to stripping a
155
- // trailing "o" to stay consistent.
156
- if (!word.empty() && word.back() == U'o') word.pop_back();
157
- return word;
158
- }
159
- if (feminine && !word.empty() && word.back() == U'o') {
160
- word.back() = U'a';
161
- }
162
- if (plural) word += U"s";
163
- return word;
164
- };
143
+ Num2Word::Num2Word() : Num2WordLayer(kNotation, kJoiners) {
144
+ add_pattern(std::make_unique<LawPattern>());
145
+ add_pattern(std::make_unique<DatePattern>(kDateFormat));
146
+ for (const auto& format : kPhoneFormats) {
147
+ add_pattern(std::make_unique<PhonePattern>(format));
148
+ }
149
+ add_pattern(std::make_unique<SuffixPattern>(Kind::ORDINAL, kOrdinalSigns, kOrdinalSignFormat));
150
+ add_pattern(std::make_unique<SuffixPattern>(Kind::ORDINAL, kOrdinalSuffixes));
151
+ add_pattern(std::make_unique<SuffixPattern>(Kind::DECADE, kDecadeSuffixes, kDecadeFormat));
152
+ }
165
153
 
166
- if (auto it = num2word::kOrdinals.find(value); it != num2word::kOrdinals.end()) {
167
- return inflect(it->second);
154
+ // ----------------------
155
+ // ----- Resolution -----
156
+ // ----------------------
157
+
158
+ bool Num2Word::accept(const Match& match, const Context& context) const {
159
+ switch (match.kind) {
160
+ case Kind::PHONE:
161
+ // 600 123 456 is a count, unless a word says it is a phone number
162
+ return match.separator != U' ' || kPhoneWords.contains(context.before());
163
+ case Kind::FRACTION:
164
+ return kFractions.contains({value(match.numbers[0]), value(match.numbers[1])});
165
+ case Kind::TIME: {
166
+ // Only with minutes; a dot makes a time only after "a las": a las 18.30, but 1.13
167
+ if (match.numbers.size() < 2) {
168
+ return false;
169
+ }
170
+ bool decimal = match.separator == U'.' && !kTimeWords.contains(context.before());
171
+ return value(match.numbers[0]) <= 24 && value(match.numbers[1]) <= 59 && !decimal;
172
+ }
173
+ case Kind::SCALE:
174
+ // 4K, 2K: a letter, read as a code
175
+ return (match.scale != U"k" && match.scale != U"K") || counted(context);
176
+ case Kind::ORDINAL:
177
+ // Ordinal words reach 999
178
+ return value(match.numbers[0]) > 0 && value(match.numbers[0]) < 1000;
179
+ default:
180
+ return true;
168
181
  }
182
+ }
183
+
184
+ NumberReading Num2Word::resolve(const Match& match, const Context& context) const {
185
+ // A decade or a compound stands alone: los 80s, 4-carriles
186
+ bool alone = match.kind == Kind::DECADE || match.kind == Kind::COMPOUND;
187
+ NumberReading reading{.one = alone ? One::UNO : one_of(context)};
169
188
 
170
- // Fallback for values without a dedicated ordinal entry: read as cardinal.
171
- return to_cardinal_int(value);
189
+ // $5.000 dólares
190
+ if (match.kind == Kind::MONEY) {
191
+ const Forms& currency = kCurrencies.at(std::u32string(match.unit));
192
+ std::u32string next = strings::to_lower(context.after());
193
+ reading.named = next == currency.one || next == currency.many || next == U"pesos";
194
+ }
195
+ return reading;
172
196
  }
173
197
 
174
- std::u32string Num2Word::to_currency(char32_t currency, std::variant<int32_t, float> number) const {
175
- auto it = num2word::kCurrencies.find(currency);
176
- if (it == num2word::kCurrencies.end()) {
177
- return std::u32string(1, currency);
198
+ // --------------------
199
+ // ----- Readings -----
200
+ // --------------------
201
+
202
+ std::u32string Num2Word::read_with(const Number& number, One one) const {
203
+ if (number.fraction.empty()) {
204
+ auto n = value_of(number.integer);
205
+ return !n || spoken_digits(number, 7) ? digits(number.integer) : cardinal(*n, one);
178
206
  }
179
207
 
180
- // Singular only for amounts that round to exactly 1 (matches the English
181
- // and French conventions).
182
- bool is_singular = std::visit([](auto&& arg) -> bool {
183
- using T = std::decay_t<decltype(arg)>;
184
- if constexpr (std::is_same_v<T, int32_t>) {
185
- return arg == 1;
186
- } else {
187
- return std::abs(arg - 1.0F) < 1e-6F;
208
+ // The separator is read as written: tres coma cinco, tres punto cinco
209
+ std::u32string fraction;
210
+ if (number.fraction.size() > 2) {
211
+ fraction = digits(number.fraction);
212
+ } else {
213
+ std::vector<std::u32string> words;
214
+ size_t zeros = number.fraction.find_first_not_of(U'0');
215
+ words.insert(words.end(), std::min(zeros, number.fraction.size()), U"cero");
216
+ if (zeros != std::u32string::npos) {
217
+ words.push_back(cardinal(value_of(number.fraction).value_or(0), one));
188
218
  }
189
- }, number);
190
-
191
- return is_singular ? it->second : num2word::kCurrenciesPlural.at(currency);
219
+ fraction = join(words);
220
+ }
221
+ std::u32string head = number.integer.empty() ? U"" : cardinal(value(number), one == One::UN ? One::UNO : one) + U" ";
222
+ return head + (number.decimal_mark == U',' ? U"coma " : U"punto ") + fraction;
192
223
  }
193
224
 
194
- std::u32string Num2Word::to_fraction(int32_t numerator, int32_t denominator) const {
195
- // Numerator takes apocope because it precedes a masculine noun (medio,
196
- // tercio, cuarto, or the masculine ordinal form).
197
- std::u32string num_word = apocopate(to_cardinal_int(numerator));
198
- bool plural = std::abs(numerator) > 1;
199
-
200
- auto with_plural = [&](std::u32string_view base) -> std::u32string {
201
- std::u32string w(base);
202
- if (plural) w += U"s";
203
- return num_word + U" " + w;
204
- };
205
-
206
- // Denominators 2/3/4 use dedicated nouns instead of the ordinal form; all
207
- // other denominators fall back to the ordinal, agreeing in number.
208
- if (denominator == 2) return with_plural(U"medio");
209
- if (denominator == 3) return with_plural(U"tercio");
210
- if (denominator == 4) return with_plural(U"cuarto");
211
-
212
- std::u32string ord = to_ordinal_int(denominator);
213
- if (plural) ord += U"s";
214
- return num_word + U" " + ord;
225
+ std::u32string Num2Word::read_number(const Number& number, const NumberReading& reading) const {
226
+ return read_with(number, reading.one);
215
227
  }
216
228
 
217
- std::u32string Num2Word::to_day(uint32_t day) const {
218
- return to_cardinal_int(static_cast<int32_t>(day));
229
+ std::u32string Num2Word::read_code_digits(std::u32string_view text) const {
230
+ auto n = value_of(text);
231
+ if ((text.size() > 1 && text[0] == U'0') || text.size() >= 7 || !n) {
232
+ return digits(text);
233
+ }
234
+ return cardinal(*n);
219
235
  }
220
236
 
221
- std::u32string Num2Word::to_month(uint32_t month) const {
222
- if (month >= 1 && month <= 12) {
223
- return num2word::kMonths[month];
237
+ std::u32string Num2Word::read_date(const Match& match, const NumberReading& reading) const {
238
+ // A law: Ley dos de dos mil dieciocho
239
+ if (match.numbers.size() == 2) {
240
+ return cardinal(value(match.numbers[0])) + U" de " + cardinal(value(match.numbers[1]));
224
241
  }
225
- return U"";
242
+
243
+ uint64_t day = value(match.numbers[0]);
244
+ return (day == 1 ? U"primero" : cardinal(day)) + U" de " + kMonths[value(match.numbers[1]) - 1] + U" de " +
245
+ cardinal(value(match.numbers[2]));
226
246
  }
227
247
 
228
- std::u32string Num2Word::to_year(uint32_t year) const {
229
- // Spanish reads years as plain cardinals (e.g. 2026 -> "dos mil veintiséis").
230
- return to_cardinal_int(static_cast<int32_t>(year));
248
+ std::u32string Num2Word::read_phone(const Match& match, const NumberReading& reading) const {
249
+ return digits(match.text);
231
250
  }
232
251
 
233
- bool Num2Word::is_ordinal_suffix(std::u32string_view suffix) const {
234
- return num2word::kOrdinalSuffixes.contains(std::u32string(suffix));
252
+ std::u32string Num2Word::read_fraction(const Match& match, const NumberReading& reading) const {
253
+ return kFractions.at({value(match.numbers[0]), value(match.numbers[1])});
235
254
  }
236
255
 
237
- std::u32string Num2Word::verbalize(const processor::num2word::StringifiedNumber& number) const {
238
- using Mode = processor::num2word::Mode;
256
+ std::u32string Num2Word::read_time(const Match& match, const NumberReading& reading) const {
257
+ uint64_t minutes = value(match.numbers[1]);
258
+ return cardinal(value(match.numbers[0]), One::UNA) + (minutes ? U" " + cardinal(minutes) : U"");
259
+ }
239
260
 
240
- // Spanish dates interleave "de" between the day, month, and year parts,
241
- // which the base (space-joined) formatter cannot express.
242
- if (number.conversionMode == Mode::DATE) {
243
- char32_t sep = (number.text.find(U'.') != std::u32string_view::npos) ? U'.' : U'-';
244
- size_t first_sep = number.text.find(sep);
245
- size_t second_sep = number.text.find(sep, first_sep + 1);
261
+ std::u32string Num2Word::read_ordinal(const Match& match, const NumberReading& reading) const {
262
+ uint64_t n = value(match.numbers[0]);
263
+ std::u32string_view suffix = match.suffix;
264
+ if (suffix == U"er" && (n == 1 || n == 3)) {
265
+ return n == 1 ? U"primer" : U"tercer";
266
+ }
267
+ bool feminine = suffix == U"ª" || suffix == U"era" || suffix == U"ra" || suffix == U"da" || suffix == U"ta" ||
268
+ suffix == U"va" || suffix == U"ma" || suffix == U"na";
269
+ return ordinal(n, feminine);
270
+ }
246
271
 
247
- std::u32string_view p1 = number.text.substr(0, first_sep);
248
- std::u32string_view p2 = number.text.substr(first_sep + 1, second_sep - first_sep - 1);
249
- std::u32string_view p3 = number.text.substr(second_sep + 1);
272
+ std::u32string Num2Word::read_decade(const Match& match, const NumberReading& reading) const {
273
+ return read_number(match.numbers[0], reading) + U"s"; // los 80s: los ochentas
274
+ }
250
275
 
251
- auto val1 = as_int(p1);
252
- auto val2 = as_int(p2);
253
- auto val3 = as_int(p3);
254
- if (!val1 || !val2 || !val3) return U"";
276
+ std::u32string Num2Word::read_money(const Number& number, const Match& match, const NumberReading& reading) const {
277
+ const Forms& currency = kCurrencies.at(std::u32string(match.unit));
278
+ One one = currency.one == U"libra" ? One::UNA : One::UN;
255
279
 
256
- // ISO: YYYY-MM-DD, otherwise DD.MM.YYYY (or DD-MM-YYYY).
257
- if (p1.size() == 4) {
258
- return to_day(static_cast<uint32_t>(*val3)) + U" de " + to_month(*val2) + U" de " + to_year(*val1);
259
- }
260
- return to_day(static_cast<uint32_t>(*val1)) + U" de " + to_month(*val2) + U" de " + to_year(*val3);
280
+ // A price: cinco dólares con cincuenta
281
+ if (number.fraction.size() == 2 && match.scale.empty()) {
282
+ Number whole{.integer = number.integer, .grouped = number.grouped};
283
+ return read_with(whole, one) + U" " + (number.integer == U"1" ? currency.one : currency.many) + U" con " +
284
+ cardinal(value_of(number.fraction).value_or(0));
261
285
  }
262
286
 
263
- std::u32string result = Num2WordLayer::verbalize(number);
264
-
265
- // The base produces "<cardinal> <currency>"; apocopate the cardinal half so
266
- // amounts of 1 (or ending in "uno") read as "un <noun>" instead of "uno <noun>".
267
- if (number.conversionMode == Mode::CURRENCY) {
268
- size_t last_space = result.rfind(U' ');
269
- if (last_space != std::u32string::npos) {
270
- std::u32string head = result.substr(0, last_space);
271
- std::u32string tail = result.substr(last_space);
272
- result = apocopate(std::move(head)) + tail;
273
- }
287
+ std::u32string words = match.scale.empty() ? read_with(number, one) : read_scale(number, match, reading);
288
+ if (reading.named) {
289
+ return words;
274
290
  }
291
+ // tres millones de dólares, but cinco mil dólares
292
+ bool of = !match.scale.empty() && kScales.at(std::u32string(match.scale)) != U"mil";
293
+ return words + (of ? U" de " : U" ") + (is_one(number) && match.scale.empty() ? currency.one : currency.many);
294
+ }
295
+
296
+ std::u32string Num2Word::read_scale(const Number& number, const Match& match, const NumberReading& reading) const {
297
+ const std::u32string& scale = kScales.at(std::u32string(match.scale));
298
+ std::u32string word = scale == U"mil" ? U"mil" : (is_one(number) ? U"millón" : U"millones");
299
+ return read_with(number, One::UN) + U" " + word;
300
+ }
301
+
302
+ std::u32string Num2Word::read_percent(const Number& number, const Match& match, const NumberReading& reading) const {
303
+ std::u32string suffix = match.suffix.empty() ? U"" : U" " + std::u32string(match.suffix);
304
+ return read_with(number, One::UNO) + U" por ciento" + suffix;
305
+ }
275
306
 
276
- return result;
307
+ std::u32string Num2Word::read_unit(const Number& number, const Match& match, const NumberReading& reading) const {
308
+ const Forms& unit = kUnits.at(std::u32string(match.unit));
309
+ std::u32string_view first_word = std::u32string_view(unit.one).substr(0, unit.one.find(U' '));
310
+ One one = feminine(first_word) ? One::UNA : One::UN;
311
+ return read_with(number, one) + U" " + (is_one(number) ? unit.one : unit.many);
277
312
  }
278
313
 
279
314
  } // namespace phonemis::es
@@ -1,30 +1,50 @@
1
1
  #pragma once
2
2
 
3
- #include <phonemis/base/processor/num2word/layer.h>
3
+ #include <phonemis/base/processor/layers/num2word/layer.h>
4
+
4
5
  #include <string>
5
- #include <variant>
6
6
 
7
7
  namespace phonemis::es {
8
8
 
9
- class Num2Word : public processor::num2word::Num2WordLayer {
9
+ // How "uno" ends a number: alone (veintiuno), before a masculine noun (veintiún años) or a feminine one (veintiuna)
10
+ enum class One { UNO = 0, UN, UNA };
11
+
12
+ // How a Spanish number is read, from the words around it.
13
+ struct NumberReading {
14
+ One one = One::UNO; // From the noun after the number
15
+ bool named = false; // $5.000 dólares: the currency is already named after the amount
16
+ };
17
+
18
+ class Num2Word : public processor::num2word::Num2WordLayer<NumberReading> {
10
19
  public:
11
- using Num2WordLayer::Num2WordLayer;
12
-
13
- char32_t decimal_separator() const override { return U','; }
14
- std::u32string to_cardinal_int(int32_t number) const override;
15
- std::u32string to_cardinal_float(float number, std::u32string_view repr) const override;
16
- std::u32string to_ordinal_int(int32_t number, std::u32string_view suffix = U"") const override;
17
- std::u32string to_currency(char32_t currency, std::variant<int32_t, float> number) const override;
18
- std::u32string to_fraction(int32_t numerator, int32_t denominator) const override;
19
- std::u32string to_day(uint32_t day) const override;
20
- std::u32string to_month(uint32_t month) const override;
21
- std::u32string to_year(uint32_t year) const override;
22
- bool is_ordinal_suffix(std::u32string_view suffix) const override;
20
+ Num2Word();
23
21
 
24
22
  protected:
25
- // Overridden so we can insert the Spanish "de" between date parts and
26
- // apply apocope ("uno" → "un") to currency amounts preceding the noun.
27
- std::u32string verbalize(const processor::num2word::StringifiedNumber& number) const override;
23
+ using Context = processor::Context;
24
+ using Match = processor::num2word::Match;
25
+ using Number = processor::num2word::Number;
26
+
27
+ // Resolution
28
+ bool accept(const Match& match, const Context& context) const override;
29
+ NumberReading resolve(const Match& match, const Context& context) const override;
30
+
31
+ // Readings
32
+ std::u32string read_number(const Number& number, const NumberReading& reading) const override;
33
+ std::u32string read_code_digits(std::u32string_view digits) const override;
34
+ std::u32string read_date(const Match& match, const NumberReading& reading) const override;
35
+ std::u32string read_phone(const Match& match, const NumberReading& reading) const override;
36
+ std::u32string read_fraction(const Match& match, const NumberReading& reading) const override;
37
+ std::u32string read_time(const Match& match, const NumberReading& reading) const override;
38
+ std::u32string read_ordinal(const Match& match, const NumberReading& reading) const override;
39
+ std::u32string read_decade(const Match& match, const NumberReading& reading) const override;
40
+ std::u32string read_money(const Number& number, const Match& match, const NumberReading& reading) const override;
41
+ std::u32string read_scale(const Number& number, const Match& match, const NumberReading& reading) const override;
42
+ std::u32string read_percent(const Number& number, const Match& match, const NumberReading& reading) const override;
43
+ std::u32string read_unit(const Number& number, const Match& match, const NumberReading& reading) const override;
44
+
45
+ private:
46
+ // A number ending with a given form of "uno", as before a currency or a unit
47
+ std::u32string read_with(const Number& number, One one) const;
28
48
  };
29
49
 
30
50
  } // namespace phonemis::es