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,244 +1,317 @@
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::fr {
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 {
14
-
15
- // Returns the position right after the last separator (space or hyphen) in `word`,
16
- // which marks the start of the last atomic cardinal token.
17
- size_t last_token_start(const std::u32string& word) {
18
- size_t pos = word.size();
19
- while (pos > 0 && word[pos - 1] != U' ' && word[pos - 1] != U'-') {
20
- pos--;
21
- }
22
- return pos;
18
+ uint64_t value(const Number& number) {
19
+ return value_of(number.integer).value_or(0);
23
20
  }
24
21
 
25
- // Converts a cardinal token to its ordinal form (e.g. "douze" -> "douzième").
26
- std::u32string cardinal_to_ordinal_token(std::u32string_view token) {
27
- if (token == U"un") return U"unième";
28
- if (token == U"cinq") return U"cinquième";
29
- if (token == U"neuf") return U"neuvième";
30
- // The plural 's' on "cents" / "quatre-vingts" is dropped for ordinals; other
31
- // tokens naturally ending in 's' (e.g. "trois") keep it.
32
- if (token == U"vingts") return U"vingtième";
33
- if (token == U"cents") return U"centième";
22
+ // ------------------------
23
+ // ----- Number words -----
24
+ // ------------------------
34
25
 
35
- std::u32string stem(token);
36
- if (!stem.empty() && stem.back() == U'e') {
37
- stem.pop_back();
26
+ std::u32string below_hundred(uint64_t n, bool feminine, bool plural_s) {
27
+ if (n < 20) {
28
+ return feminine && n == 1 ? U"une" : std::u32string(kOnes[n]);
29
+ }
30
+
31
+ // soixante-dix, quatre-vingt-dix
32
+ uint64_t t = n / 10, u = n % 10;
33
+ if (t == 7 || t == 9) {
34
+ t--;
35
+ u += 10;
36
+ }
37
+ if (u == 0) {
38
+ return std::u32string(kTens[t]) + (t == 8 && plural_s ? U"s" : U"");
38
39
  }
39
- return stem + U"ième";
40
+ std::u32string unit = feminine && u == 1 ? U"une" : std::u32string(kOnes[u]);
41
+ return std::u32string(kTens[t]) + ((u == 1 || u == 11) && t < 8 ? U" et " : U"-") + unit;
40
42
  }
41
43
 
42
- } // namespace
44
+ std::u32string below_thousand(uint64_t n, bool feminine, bool plural_s) {
45
+ uint64_t h = n / 100, r = n % 100;
46
+ if (h == 0) {
47
+ return below_hundred(r, feminine, plural_s);
48
+ }
49
+ std::u32string head = h == 1 ? U"cent" : std::u32string(kOnes[h]) + U" cent" + (r == 0 && plural_s ? U"s" : U"");
50
+ return head + (r ? U" " + below_hundred(r, feminine, plural_s) : U"");
51
+ }
43
52
 
44
- std::u32string Num2Word::to_cardinal_int(int32_t value) const {
45
- if (value < 0) {
46
- return U"moins " + to_cardinal_int(std::abs(value));
53
+ // A cardinal; `plural_s` is false when "mille" follows (deux cent mille, quatre-vingt mille).
54
+ std::u32string cardinal(uint64_t n, bool feminine = false, bool plural_s = true) {
55
+ if (n < 1000) {
56
+ return below_thousand(n, feminine, plural_s);
57
+ }
58
+ if (n < 1000000) {
59
+ uint64_t t = n / 1000, r = n % 1000;
60
+ std::u32string head = t == 1 ? U"mille" : below_thousand(t, false, false) + U" mille";
61
+ return head + (r ? U" " + below_thousand(r, feminine, plural_s) : U"");
47
62
  }
63
+ for (auto [scale, word] : {std::pair{1000000000ULL, U"milliard"}, std::pair{1000000ULL, U"million"}}) {
64
+ if (n >= scale) {
65
+ uint64_t q = n / scale, r = n % scale;
66
+ std::u32string head = cardinal(q) + U" " + std::u32string(word) + (q > 1 ? U"s" : U"");
67
+ return head + (r ? U" " + cardinal(r, feminine, plural_s) : U"");
68
+ }
69
+ }
70
+ return U"";
71
+ }
48
72
 
49
- if (num2word::kCardinals.contains(value)) {
50
- return num2word::kCardinals.at(value);
73
+ std::u32string ordinal(uint64_t n, bool feminine = false) {
74
+ if (n == 1) {
75
+ return feminine ? U"première" : U"premier";
51
76
  }
52
77
 
53
- if (value < 70) {
54
- // Regular tens-units composition with "et" insertion for *1 values (e.g. 21, 31...).
55
- int32_t tens = (value / 10) * 10;
56
- int32_t units = value % 10;
57
- std::u32string sep = (units == 1) ? U" et " : U" ";
58
- return num2word::kCardinals.at(tens) + sep + num2word::kCardinals.at(units);
78
+ // vingtième, cinquième, neuvième, onzième
79
+ std::u32string words = cardinal(n);
80
+ if (words.ends_with(U"vingts") || words.ends_with(U"cents")) {
81
+ words.pop_back();
82
+ }
83
+ if (words.ends_with(U"neuf")) {
84
+ words.back() = U'v';
85
+ } else if (words.ends_with(U"cinq")) {
86
+ words += U"u";
87
+ }
88
+ if (words.ends_with(U'e')) {
89
+ words.pop_back();
59
90
  }
91
+ return words + U"ième";
92
+ }
60
93
 
61
- if (value < 80) {
62
- // 70-79: "soixante" base with an extended units word (dix, onze, ..., dix neuf).
63
- int32_t units = value - 60;
64
- if (units == 11) return U"soixante et onze";
65
- return U"soixante " + num2word::kCardinals.at(units);
94
+ std::u32string digits(std::u32string_view text) {
95
+ std::vector<std::u32string> words;
96
+ for (char32_t c : text) {
97
+ words.emplace_back(kOnes[c - U'0']);
66
98
  }
99
+ return join(words);
100
+ }
101
+
102
+ // -------------------
103
+ // ----- Context -----
104
+ // -------------------
67
105
 
68
- if (value < 100) {
69
- // 80-99: "quatre vingt(s)" base, no "et" even at 81/91.
70
- int32_t units = value - 80;
71
- if (units == 0) return U"quatre vingts";
72
- return U"quatre vingt " + num2word::kCardinals.at(units);
106
+ bool feminine(std::u32string_view noun) {
107
+ std::u32string word = strings::to_lower(noun);
108
+ word = word.substr(word.find_last_of(U'-') + 1);
109
+ if (!kFeminineNouns.contains(word) && word.ends_with(U's')) {
110
+ word.pop_back();
73
111
  }
112
+ if (kFeminineNouns.contains(word)) {
113
+ return true;
114
+ }
115
+ bool masculine_ending = std::ranges::any_of(kMasculineEndings, [&](const auto& e) { return word.ends_with(e); });
116
+ bool date = std::ranges::find(kMonths, word) != kMonths.end() || kWeekdays.contains(word);
117
+ return word.ends_with(U'e') && !kMasculineInE.contains(word) && !date && !masculine_ending;
118
+ }
74
119
 
75
- // Handle large numbers by iterating through the large scales map (cent, mille, million, ...)
76
- // in descending order to find the largest applicable base.
77
- for (auto it = num2word::kLargeCardinals.rbegin(); it != num2word::kLargeCardinals.rend(); ++it) {
78
- int64_t base = it->first;
79
- if (static_cast<int64_t>(value) >= base) {
80
- int32_t high = value / static_cast<int32_t>(base);
81
- int32_t low = value % static_cast<int32_t>(base);
120
+ // A lowercase noun follows: 10k abonnés
121
+ bool counted(const Context& context) {
122
+ std::u32string word = context.after();
123
+ bool lowercase_word = word.size() > 2 && std::ranges::all_of(word, [](char32_t c) { return unicode::islower(c); });
124
+ return lowercase_word && !kStopWords.contains(word) && !kNumberWords.contains(word);
125
+ }
82
126
 
83
- // "cent" and "mille" drop the leading "un" when used as multiplier of 1.
84
- std::u32string head;
85
- if (high == 1 && (base == 100LL || base == 1000LL)) {
86
- head = U"";
87
- } else {
88
- head = to_cardinal_int(high) + U" ";
89
- }
127
+ // A noun after a number is singular below 2: un virgule cinq kilomètre, deux kilomètres
128
+ const std::u32string& number_form(const Number& number, const Forms& forms) {
129
+ return value(number) < 2 ? forms.one : forms.many;
130
+ }
131
+ } // namespace
90
132
 
91
- std::u32string scale = it->second;
92
- // "cent" takes an 's' when multiplied and not followed by a smaller part.
93
- // "million"/"milliard" pluralize as normal nouns when multiplied.
94
- // "mille" is invariable.
95
- if (base == 100LL && high > 1 && low == 0) {
96
- scale += U"s";
97
- } else if (base >= 1000000LL && high > 1) {
98
- scale += U"s";
99
- }
133
+ Num2Word::Num2Word() : Num2WordLayer(kNotation, kJoiners) {
134
+ add_pattern(std::make_unique<DatePattern>(kDateFormat));
135
+ add_pattern(std::make_unique<PhonePattern>(kPhoneFormat));
136
+ add_pattern(std::make_unique<SuffixPattern>(Kind::ORDINAL, kOrdinalSuffixes));
137
+ add_pattern(std::make_unique<RomanOrdinalPattern>());
138
+ }
100
139
 
101
- std::u32string res = head + scale;
102
- if (low > 0) {
103
- res += U" " + to_cardinal_int(low);
140
+ // -----------------------
141
+ // ----- Resolution -----
142
+ // -----------------------
143
+
144
+ bool Num2Word::accept(const Match& match, const Context& context) const {
145
+ switch (match.kind) {
146
+ case Kind::DATE:
147
+ // Without a year only a zero-padded day or month is a date: 05/11, but not 3/4
148
+ return match.numbers.size() == 3 || match.numbers[0].integer[0] == U'0' || match.numbers[1].integer[0] == U'0';
149
+ case Kind::TIME:
150
+ if (match.numbers.size() == 2) {
151
+ bool decimal = match.separator == U'.' && !kTimeWords.contains(context.before());
152
+ return value(match.numbers[0]) <= 24 && value(match.numbers[1]) <= 59 && !decimal;
104
153
  }
105
- return res;
106
- }
154
+ return true;
155
+ case Kind::SCALE:
156
+ // 4K, 3k de Q: a letter, read as a code
157
+ return kScales.at(std::u32string(match.scale)) != U"mille" || counted(context);
158
+ default:
159
+ return true;
107
160
  }
108
-
109
- return conversions::utf8_to_u32(std::to_string(value));
110
161
  }
111
162
 
112
- std::u32string Num2Word::to_cardinal_float(float value, std::u32string_view repr) const {
113
- if (value < 0.0f) {
114
- return U"moins " + to_cardinal_float(std::abs(value), repr);
115
- }
163
+ NumberReading Num2Word::resolve(const Match& match, const Context& context) const {
164
+ std::u32string previous = context.before();
165
+ return {.feminine = feminine(context.after()),
166
+ .plural_s = previous != U"années" && previous != U"année",
167
+ .equation = match.kind == Kind::DIMENSION && context.tail().find(U'=') != std::u32string_view::npos};
168
+ }
116
169
 
117
- // The base transform normalizes the decimal separator to '.', but accept ',' too
118
- // for direct callers.
119
- std::string value_str = conversions::u32_to_utf8(repr);
120
- std::replace(value_str.begin(), value_str.end(), ',', '.');
170
+ // --------------------
171
+ // ----- Readings -----
172
+ // --------------------
121
173
 
122
- // Trim trailing zeros in the fractional part and a dangling decimal point.
123
- auto rit = std::find_if(value_str.rbegin(), value_str.rend(),
124
- [](char c) { return c != '0'; });
125
- value_str = std::string(value_str.begin(), rit.base());
126
- if (!value_str.empty() && value_str.back() == '.') {
127
- value_str.pop_back();
174
+ std::u32string Num2Word::read_gendered(const Number& number, const NumberReading& reading, bool feminine) const {
175
+ if (number.fraction.empty()) {
176
+ auto n = value_of(number.integer);
177
+ return !n || spoken_digits(number, 5) ? digits(number.integer) : cardinal(*n, feminine, reading.plural_s);
128
178
  }
129
179
 
130
- size_t dot_pos = value_str.find('.');
131
- if (dot_pos == std::string::npos) {
132
- return to_cardinal_int(value_str.empty() ? 0 : std::stoi(value_str));
180
+ // Up to three decimals read as a number: zéro virgule zéro cinq, deux virgule soixante-quinze
181
+ std::u32string fraction;
182
+ if (number.fraction.size() > 3) {
183
+ fraction = digits(number.fraction);
184
+ } else {
185
+ std::vector<std::u32string> words;
186
+ size_t zeros = number.fraction.find_first_not_of(U'0');
187
+ words.insert(words.end(), std::min(zeros, number.fraction.size()), U"zéro");
188
+ if (zeros != std::u32string::npos) {
189
+ words.push_back(cardinal(value_of(number.fraction).value_or(0)));
190
+ }
191
+ fraction = join(words);
133
192
  }
193
+ std::u32string head = number.integer.empty() ? U"" : cardinal(value(number), feminine) + U" ";
194
+ return head + U"virgule " + fraction;
195
+ }
134
196
 
135
- std::string integer_part_str = value_str.substr(0, dot_pos);
136
- std::string fractional_part_str = value_str.substr(dot_pos + 1);
137
-
138
- int32_t integer_part = integer_part_str.empty() ? 0 : std::stoi(integer_part_str);
197
+ std::u32string Num2Word::read_number(const Number& number, const NumberReading& reading) const {
198
+ return read_gendered(number, reading, number.fraction.empty() && reading.feminine);
199
+ }
139
200
 
140
- // French verbalizes the fractional part as a single cardinal number
141
- // (e.g. "45" -> "quarante cinq"), but any leading zeros preserve their value
142
- // as spoken "zéro" words (e.g. "05" -> "zéro cinq").
143
- std::u32string frac_words;
144
- size_t pos = 0;
145
- while (pos < fractional_part_str.size() && fractional_part_str[pos] == '0') {
146
- if (!frac_words.empty()) frac_words += U" ";
147
- frac_words += U"zéro";
148
- pos++;
149
- }
150
- if (pos < fractional_part_str.size()) {
151
- if (!frac_words.empty()) frac_words += U" ";
152
- frac_words += to_cardinal_int(std::stoi(fractional_part_str.substr(pos)));
201
+ std::u32string Num2Word::read_code_digits(std::u32string_view text) const {
202
+ auto n = value_of(text);
203
+ if ((text.size() > 1 && text[0] == U'0') || text.size() > 4 || !n) {
204
+ return digits(text);
153
205
  }
206
+ return cardinal(*n);
207
+ }
154
208
 
155
- return to_cardinal_int(integer_part) + U" virgule " + frac_words;
209
+ std::u32string Num2Word::read_date(const Match& match, const NumberReading& reading) const {
210
+ uint64_t day = value(match.numbers[0]);
211
+ std::u32string words = (day == 1 ? ordinal(1) : cardinal(day)) + U" " + kMonths[value(match.numbers[1]) - 1];
212
+ return match.numbers.size() < 3 ? words : words + U" " + cardinal(value(match.numbers[2]));
156
213
  }
157
214
 
158
- std::u32string Num2Word::to_ordinal_int(int32_t value, std::u32string_view suffix) const {
159
- // "premier"/"première" are the only fully irregular ordinals; they do not appear
160
- // as a suffix in compounds (21 -> "vingt et unième"), so we only apply them
161
- // when the value is exactly 1. The suffix disambiguates masculine vs. feminine.
162
- if (value == 1) {
163
- bool feminine = (suffix == U"re" || suffix == U"res" ||
164
- suffix == U"ère" || suffix == U"ères");
165
- return feminine ? U"première" : U"premier";
215
+ std::u32string Num2Word::read_phone(const Match& match, const NumberReading& reading) const {
216
+ // In pairs: zéro six douze trente-quatre ...
217
+ std::vector<std::u32string> words;
218
+ for (const auto& pair : match.numbers) {
219
+ bool zero = pair.integer.size() == 2 && pair.integer[0] == U'0';
220
+ if (pair.integer.size() > 3) {
221
+ words.push_back(digits(pair.integer)); // A longer group of a foreign number
222
+ } else {
223
+ words.push_back(zero ? U"zéro " + std::u32string(kOnes[pair.integer[1] - U'0']) : cardinal(value(pair)));
224
+ }
166
225
  }
226
+ return join(words);
227
+ }
167
228
 
168
- std::u32string card = to_cardinal_int(value);
169
- size_t split = last_token_start(card);
170
- std::u32string prefix = card.substr(0, split);
171
- std::u32string_view last = std::u32string_view(card).substr(split);
229
+ std::u32string Num2Word::read_fraction(const Match& match, const NumberReading& reading) const {
230
+ uint64_t a = value(match.numbers[0]), b = value(match.numbers[1]);
231
+ auto it = kFractions.find({a, b});
232
+ return it != kFractions.end() ? it->second : cardinal(a) + U" sur " + cardinal(b);
233
+ }
172
234
 
173
- return prefix + cardinal_to_ordinal_token(last);
235
+ std::u32string Num2Word::read_time(const Match& match, const NumberReading& reading) const {
236
+ uint64_t hours = value(match.numbers[0]);
237
+ std::u32string words = cardinal(hours, true) + (hours < 2 ? U" heure" : U" heures");
238
+ if (match.numbers.size() == 2 && value(match.numbers[1]) > 0) {
239
+ words += U" " + cardinal(value(match.numbers[1]), true);
240
+ }
241
+ return words;
174
242
  }
175
243
 
176
- std::u32string Num2Word::to_currency(char32_t currency, std::variant<int32_t, float> number) const {
177
- if (!num2word::kCurrencies.contains(currency)) {
178
- return std::u32string(1, currency);
244
+ std::u32string Num2Word::read_ordinal(const Match& match, const NumberReading& reading) const {
245
+ std::u32string_view suffix = match.suffix;
246
+ std::u32string words;
247
+ if (suffix.starts_with(U"nd")) {
248
+ words = suffix.starts_with(U"nde") ? U"seconde" : U"second";
249
+ } else {
250
+ bool feminine = suffix == U"re" || suffix == U"ère" || suffix == U"res" || suffix == U"ères";
251
+ words = ordinal(value(match.numbers[0]), feminine);
179
252
  }
253
+ return words + (suffix.ends_with(U's') ? U"s" : U"");
254
+ }
180
255
 
181
- std::u32string result = num2word::kCurrencies.at(currency);
256
+ std::u32string Num2Word::read_money(const Number& number, const Match& match, const NumberReading& reading) const {
257
+ Forms currency = kCurrencies.at(std::u32string(match.unit));
258
+ std::u32string scale(match.scale);
259
+ if (match.unit == U"M€") {
260
+ scale = U"millions";
261
+ currency = {U"euro", U"euros"};
262
+ }
182
263
 
183
- // French pluralization follows the same |value| > 1 heuristic as English:
184
- // singular only for an amount that rounds to exactly 1.
185
- bool is_singular = std::visit([](auto&& arg) -> bool {
186
- using T = std::decay_t<decltype(arg)>;
187
- if constexpr (std::is_same_v<T, int32_t>) {
188
- return arg == 1;
189
- } else {
190
- return std::abs(arg - 1.0F) < 1e-6F;
264
+ if (!scale.empty()) {
265
+ // trois millions d'euros, but dix mille euros
266
+ std::u32string words = read_scale(number, Match{.scale = scale}, reading);
267
+ if (kScales.at(scale) == U"mille") {
268
+ return words + U" " + currency.many;
191
269
  }
192
- }, number);
270
+ bool vowel = strings::contains(std::u32string_view(U"aeiouyéh"), currency.many[0]);
271
+ return words + (vowel ? U" d'" : U" de ") + currency.many;
272
+ }
193
273
 
194
- if (!is_singular) {
195
- result += U"s";
274
+ // A price: trois euros cinquante, quatre-vingt-dix-neuf centimes
275
+ bool feminine = currency.one == U"livre";
276
+ if (number.fraction.size() == 2) {
277
+ uint64_t cents = value_of(number.fraction).value_or(0);
278
+ if (value(number) == 0) {
279
+ return cardinal(cents) + U" centimes";
280
+ }
281
+ Number whole{.integer = number.integer, .grouped = number.grouped};
282
+ return read_gendered(whole, reading, feminine) + U" " + (number.integer == U"1" ? currency.one : currency.many) +
283
+ U" " + cardinal(cents);
196
284
  }
197
- return result;
285
+ return read_gendered(number, reading, feminine) + U" " + number_form(number, currency);
198
286
  }
199
287
 
200
- std::u32string Num2Word::to_month(uint32_t month) const {
201
- if (month >= 1 && month <= 12) {
202
- return num2word::kMonths[month];
288
+ std::u32string Num2Word::read_scale(const Number& number, const Match& match, const NumberReading& reading) const {
289
+ const std::u32string& word = kScales.at(std::u32string(match.scale));
290
+ if (word == U"mille") {
291
+ return read_gendered(number, reading, false) + U" mille";
203
292
  }
204
- return U"";
205
- }
206
293
 
207
- std::u32string Num2Word::to_year(uint32_t year) const {
208
- // French reads years as plain cardinals (e.g. 2026 -> "deux mille vingt six"),
209
- // unlike the English "twenty twenty-six" style.
210
- return to_cardinal_int(static_cast<int32_t>(year));
294
+ // trois millions, un virgule cinq million
295
+ std::u32string one = word.ends_with(U's') ? word.substr(0, word.size() - 1) : word;
296
+ return read_gendered(number, reading, false) + U" " + number_form(number, {one, one + U"s"});
211
297
  }
212
298
 
213
- bool Num2Word::is_ordinal_suffix(std::u32string_view suffix) const {
214
- return num2word::kOrdinalSuffixes.contains(std::u32string(suffix));
299
+ std::u32string Num2Word::read_percent(const Number& number, const Match& match, const NumberReading& reading) const {
300
+ std::u32string suffix = match.suffix.empty() ? U"" : U" " + std::u32string(match.suffix);
301
+ return read_gendered(number, reading, false) + U" pour cent" + suffix;
215
302
  }
216
303
 
217
- std::u32string Num2Word::to_fraction(int32_t numerator, int32_t denominator) const {
218
- // Common fractions have dedicated French nouns instead of the ordinal form,
219
- // and the denominator noun agrees in number with the numerator.
220
- std::u32string num_word = to_cardinal_int(numerator);
221
- bool plural = std::abs(numerator) > 1;
222
-
223
- auto with_plural = [&](std::u32string_view base) {
224
- std::u32string w(base);
225
- if (plural) w += U"s";
226
- return num_word + U" " + w;
227
- };
228
-
229
- if (denominator == 2) return with_plural(U"demi");
230
- if (denominator == 3) return with_plural(U"tiers");
231
- if (denominator == 4) return with_plural(U"quart");
232
-
233
- std::u32string ord = to_ordinal_int(denominator);
234
- if (plural) ord += U"s";
235
- return num_word + U" " + ord;
304
+ std::u32string Num2Word::read_unit(const Number& number, const Match& match, const NumberReading& reading) const {
305
+ const Forms& unit = kUnits.at(std::u32string(match.unit));
306
+ std::u32string_view first_word = std::u32string_view(unit.one).substr(0, unit.one.find(U' '));
307
+ return read_gendered(number, reading, feminine(first_word)) + U" " + number_form(number, unit);
236
308
  }
237
309
 
238
- std::u32string Num2Word::to_day(uint32_t day) const {
239
- // French dates read the day as a cardinal, except for the first of the month.
240
- if (day == 1) return to_ordinal_int(1);
241
- return to_cardinal_int(static_cast<int32_t>(day));
310
+ std::u32string Num2Word::read_joiner(const Match& match, const NumberReading& reading) const {
311
+ if (match.kind == Kind::DIMENSION) {
312
+ return reading.equation ? U" fois " : U" par ";
313
+ }
314
+ return Num2WordLayer::read_joiner(match, reading);
242
315
  }
243
316
 
244
317
  } // namespace phonemis::fr
@@ -1,25 +1,48 @@
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::fr {
8
8
 
9
- class Num2Word : public processor::num2word::Num2WordLayer {
9
+ // How a French number is read, from the words around it.
10
+ struct NumberReading {
11
+ bool feminine = false; // vingt et une heures: before a feminine noun
12
+ bool plural_s = true; // quatre-vingts, deux cents; but les années quatre-vingt
13
+ bool equation = false; // 12 x 4 = 48: "x" is "fois" rather than "par"
14
+ };
15
+
16
+ class Num2Word : public processor::num2word::Num2WordLayer<NumberReading> {
10
17
  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;
18
+ Num2Word();
19
+
20
+ protected:
21
+ using Context = processor::Context;
22
+ using Match = processor::num2word::Match;
23
+ using Number = processor::num2word::Number;
24
+
25
+ // Resolution
26
+ bool accept(const Match& match, const Context& context) const override;
27
+ NumberReading resolve(const Match& match, const Context& context) const override;
28
+
29
+ // Readings
30
+ std::u32string read_number(const Number& number, const NumberReading& reading) const override;
31
+ std::u32string read_code_digits(std::u32string_view digits) const override;
32
+ std::u32string read_date(const Match& match, const NumberReading& reading) const override;
33
+ std::u32string read_phone(const Match& match, const NumberReading& reading) const override;
34
+ std::u32string read_fraction(const Match& match, const NumberReading& reading) const override;
35
+ std::u32string read_time(const Match& match, const NumberReading& reading) const override;
36
+ std::u32string read_ordinal(const Match& match, const NumberReading& reading) const override;
37
+ std::u32string read_money(const Number& number, const Match& match, const NumberReading& reading) const override;
38
+ std::u32string read_scale(const Number& number, const Match& match, const NumberReading& reading) const override;
39
+ std::u32string read_percent(const Number& number, const Match& match, const NumberReading& reading) const override;
40
+ std::u32string read_unit(const Number& number, const Match& match, const NumberReading& reading) const override;
41
+ std::u32string read_joiner(const Match& match, const NumberReading& reading) const override;
42
+
43
+ private:
44
+ // A number with an explicit gender, as before a currency or a unit
45
+ std::u32string read_gendered(const Number& number, const NumberReading& reading, bool feminine) const;
23
46
  };
24
47
 
25
48
  } // namespace phonemis::fr