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
@@ -0,0 +1,642 @@
1
+ # Phonemis: Code Style and Logic Modelling Notes
2
+
3
+ These notes describe how the author writes and structures code in `src/phonemis`. Use them to write
4
+ new code (a language, a component, a fix) that reads like the author wrote it.
5
+
6
+ ## 0. Sources and weighting
7
+
8
+ - **Primary evidence** (hand-written by the author, confirmed with `git blame`):
9
+ - `base/`: pipeline, phonemizer core, lexicon and hybrid phonemizers, tokenizer, tagger
10
+ interface, processor and layers.
11
+ - `lang/en/*`, except `num2word.cpp`.
12
+ - Every `lang/*/pipeline.h`.
13
+ - `utils/*`.
14
+ - `protophone/{tensor,tensor_view,tensor_utils,types,meta,numeric}.h`.
15
+ - **Excluded or weighted lower:**
16
+ - `lang/*/num2word.cpp` and `protophone/protophone.cpp`, which are mostly AI-generated.
17
+ - The long linguistic commentary in the non-English `constants.h` files. It was written
18
+ together with the num2word code.
19
+ - Commit `c8d8744`, an external AI-assisted refactor. It rewrote `tagger/hmm_tagger.*` and
20
+ `nn/tokenizer.*` and split `num2word/layer.cpp` into helpers.
21
+ - Commit `36cef09`, which added `phonemize_words()` to `ipipeline.cpp`.
22
+ - The comment style of these commits is **not** the author's voice (see §9).
23
+
24
+ ---
25
+
26
+ ## 1. Modelling the logic (architecture)
27
+
28
+ ### 1.1 Three-stage pipeline behind a facade
29
+ - Every language is an `IPipeline` with three overridable stages. The base `operator()` runs
30
+ them in order:
31
+ ```cpp
32
+ class IPipeline {
33
+ public:
34
+ virtual ~IPipeline() = default;
35
+ virtual std::u32string operator()(std::u32string_view text, bool preprocess = true, bool postprocess = true);
36
+ // A processing parts to be implemented by derived classes.
37
+ virtual std::u32string preprocess(const std::u32string& input) = 0;
38
+ virtual std::u32string process(const std::u32string& input) = 0;
39
+ virtual std::u32string postprocess(const std::u32string& input) = 0;
40
+ };
41
+ ```
42
+ - The public `Pipeline` class is a facade over `std::unique_ptr<IPipeline> impl_`:
43
+ - A private static factory, `create_pipeline(const Config&)`, chooses the implementation.
44
+ - The factory is a flat `if` chain on language codes. Each line ends with a comment naming the
45
+ language (`// German`).
46
+ - It throws `std::invalid_argument` for an empty or unsupported language.
47
+ - Every public method is a one-line delegation to `impl_`.
48
+ - Each stage is public on its own (`preprocess`/`process`/`postprocess`), as are the `preprocess`
49
+ and `postprocess` flags. This keeps stages testable and lets callers bypass them.
50
+ - There are UTF-8 (`std::string_view`) and UTF-32 (`std::u32string_view`) overloads of the entry
51
+ points. The UTF-8 overload converts the input and forwards to the UTF-32 one.
52
+
53
+ ### 1.2 Template Method everywhere: the base owns the loop, the subclass handles one unit
54
+ | Base driver (implemented once) | Hooks for subclasses |
55
+ |---|---|
56
+ | `IPipeline::operator()` | `preprocess` / `process` / `postprocess` (`= 0`) |
57
+ | `Phonemizer::phonemize(std::span<const Token>)` | `phonemize(const Token&) const = 0`, `update_context(idx, tokens)` (no-op by default) |
58
+ | `Tagger::tag(std::span<Token>)` (splits the stream on EOS characters) | `tag_sentence(std::span<Token>) const = 0` |
59
+ | `Num2WordLayer<Reading>::apply()` (each pattern rewrites a draft: scan → `accept` → `resolve` → verbalize) | `resolve`, `read_number`, `read_code_digits` (`= 0`), `accept`, `read_date`, `read_money`, … (defaults) |
60
+ | `HMMTagger::tag_sentence()` | `should_lowercase(word)`: protected virtual, defaults to `false`, English overrides it |
61
+
62
+ - Per-unit hooks are `const` (pure lookups). All state changes go through one hook that is
63
+ explicitly non-const (`update_context`), and its `@details` says why:
64
+ > `@details Non-const as it manages stateful context updates across the sequence.`
65
+ > `@details Const as it is a pure lookup based on current internal state.`
66
+
67
+ ### 1.3 A pipeline is a composition of submodules
68
+ ```cpp
69
+ private:
70
+ // Required submodules
71
+ processor::Preprocessor preprocessor_;
72
+ tokenizer::Tokenizer tokenizer_;
73
+ phonemizer::HybridPhonemizer<en::LexiconPhonemizer, phonemizer::nn::NeuralPhonemizer> phonemizer_;
74
+
75
+ // Optional submodules
76
+ std::unique_ptr<tagger::HMMTagger> tagger_ = nullptr;
77
+ ```
78
+ - Required parts are value members. Optional parts are a `unique_ptr`, created only when their
79
+ config is present and checked with `if (tagger_)`.
80
+ - `HybridPhonemizer` is a template constrained with C++20 concepts:
81
+ `template <std::derived_from<LexiconPhonemizer> LXP, std::derived_from<nn::NeuralPhonemizer> NNP>`.
82
+ - It owns both sub-phonemizers through `unique_ptr`.
83
+ - A sub-phonemizer exists only if its file path was given: "Not passing filepath … disables it".
84
+ - Lookup order is lexicon first, then the neural model as a fallback, written as ternaries on
85
+ the pointers.
86
+
87
+ ### 1.4 Layered text processing (chain of transformations)
88
+ - The interface is `processor::Layer`, with
89
+ `virtual std::u32string transform(std::u32string_view input) const = 0;`.
90
+ - `Processor` holds a `std::vector<std::unique_ptr<Layer>>`, exposes `add_layer(...)`, and
91
+ `process()` applies the layers in order.
92
+ - Role names are aliases, not new types:
93
+ `using Preprocessor = Processor; using Postprocessor = Processor; // Naming abstraction`.
94
+ - Generic layers are configured with callables rather than subclasses. `SanitizerLayer(Filter, Mapper)`
95
+ takes `std::function` aliases whose defaults are identity lambdas. Language pipelines pass small
96
+ lambdas that look up a table from `constants.h`.
97
+
98
+ ### 1.5 Language specialisation is data first, subclasses second
99
+ - Generic components receive language data as non-owning pointers to static tables:
100
+ `tokenizer_(&constants::tokenizer::kSpecialCharacters, &constants::tokenizer::kExceptions)`.
101
+ - A language is mostly tables in `lang/xx/constants.h`: split rules, exception words, number
102
+ words, currencies, months, and character replacements.
103
+ - Subclass only where tables are not enough (`en::LexiconPhonemizer`, `en::HMMTagger`,
104
+ `xx::Num2Word`).
105
+ - A subclass **reuses the base class name inside the language namespace**: `phonemis::en::Pipeline`,
106
+ `phonemis::en::LexiconPhonemizer`, `phonemis::en::HMMTagger`.
107
+ - Constructors are inherited: `using tagger::HMMTagger::HMMTagger;`, `using Num2WordLayer::Num2WordLayer;`.
108
+ - The base class alias pattern:
109
+ ```cpp
110
+ // A shortcut for base class calls
111
+ using Base = phonemizer::LexiconPhonemizer;
112
+ using Base::phonemize; // un-hide the overloaded base method
113
+ ...
114
+ auto result = Base::lookup(utf8_word, tag);
115
+ ```
116
+ - When a language needs a modified config, a small private static helper copies it and patches
117
+ only the missing fields (`hi::Pipeline::make_phonemizer_config`).
118
+
119
+ ### 1.6 Configuration modelling
120
+ - Each module has one `struct Config` in its own `config.h`, inside the module's namespace
121
+ (`phonemis::Config`, `phonemizer::Config`, `tagger::Config`, `num2word::Config`).
122
+ - The top-level `Config` aggregates sub-configs. A required sub-config is a plain member; an
123
+ optional one is wrapped: `std::optional<tagger::Config> tagger;`.
124
+ - Optional resources are `std::optional<std::string> xxx_filepath = std::nullopt;`. A missing
125
+ resource **disables the feature**, documented as `@details If not provided, … is disabled.`
126
+ - Overrides of default tables are raw pointers to externally owned data, defaulting to null:
127
+ `const std::unordered_map<char32_t, int64_t>* nn_grapheme_mapping = nullptr;`.
128
+ - Every field has its own `/** … */` block, with a blank line between fields.
129
+
130
+ ### 1.7 Plain data structs carry state between stages
131
+ - `Token` holds the text, context flags (`first`, `whitespace`) and optional decorations
132
+ (`std::optional<tagger::Tag> tag`).
133
+ - Decorator modules such as the tagger annotate tokens **in place**, rather than producing
134
+ parallel arrays.
135
+ - Position is stored as flags, not offsets.
136
+ - Small named structs are used instead of tuples or out-parameters: `NumberMatch {len, mode}`,
137
+ `GlobalContext`, `Weights<T> {weight, bias}`, `Range<T> {begin, end}`. Every field gets a default
138
+ member initializer.
139
+
140
+ ### 1.8 Enums encode rules, and their order means something
141
+ - `enum class` is used for rule sets and modes: `split::Rule`, `num2word::Mode`,
142
+ `stress::Level : int32_t`.
143
+ - Each enumerator gets a short doc comment, often with an example:
144
+ `// Separator attached to the start of the following word (e.g., "well", "-being")`.
145
+ - Values are chosen so that comparisons make sense: `UNSTRESSED = -3 … NORMAL = 0 … FORCED = 3`
146
+ allows `*stress >= stress::Level::NORMAL`. The first enumerator is explicitly `= 0`.
147
+ - Blank lines group related enumerators (`POTENTIALLY_ORDINAL, ORDINAL` / `FRACTION, CURRENCY`).
148
+
149
+ ### 1.9 Stateless logic goes in free functions in a namespace
150
+ - Example: `en::stress::apply(std::u32string& phonemes, Level)` and `en::stress::restress(...)`.
151
+ They are in-place and have no class around them.
152
+ - All utilities are namespaces of free functions, often templates: `utils::strings`,
153
+ `utils::unicode`, `utils::conversions`, `utils::io`, `protophone::numeric`, `protophone::meta`,
154
+ `protophone::utils`.
155
+
156
+ ### 1.10 Choosing the backend at build time
157
+ - `#ifdef ET_ON` switches the includes, the member type (`std::unique_ptr<executorch::…::Module>`
158
+ vs `std::unique_ptr<protophone::Protophone>`), and the inference code. Both branches sit side by
159
+ side inside the same function.
160
+
161
+ ### 1.11 Protophone (the in-house tensor library)
162
+ - The vocabulary mirrors PyTorch:
163
+ - `Tensor<T>` owns its data (`std::vector<T, xsimd::default_allocator<T>>`).
164
+ - `TensorView<T>` is non-owning: pointer, shape, strides and offset.
165
+ - `reshape`, `slice(args...)` and `transpose(dim0 = 0, dim1 = 1)` all return new views by value.
166
+ - Variadic slicing arguments are normalised to `std::variant<size_t, Range<size_t>, All>` in
167
+ `meta::to_slice_variant` (with `if constexpr`).
168
+ - In-place operations are free functions declared as friends (`utils::repack`) rather than member
169
+ methods.
170
+ - Comment headings group members: `// Friends declarations`, `// Tensor data`,
171
+ `// Tensor metadata`, `// Simple accessors` (one-line inline accessors).
172
+ - Forward declarations are collected in a commented block to break header cycles.
173
+
174
+ ---
175
+
176
+ ## 2. Domain logic patterns (G2P)
177
+
178
+ ### 2.1 Cascade from most specific to most generic, with early returns
179
+ The order in `en::LexiconPhonemizer::phonemize`:
180
+ 1. `lookup_special`: hand-coded special words (a/an/the/to/in/am/used/supposed/…), with context.
181
+ 2. Text in all capitals → `lookup_nnp` (acronyms, spelled out letter by letter).
182
+ 3. Exact lexicon entry (`is_known`), then apostrophe variants (`s'` → `'s`, trailing `'`).
183
+ 4. Morphological stems: `lookup_stem_s`, then `lookup_stem_ed`, then `lookup_stem_ing`.
184
+ 5. `std::nullopt`. The caller (`HybridPhonemizer`) falls back to the neural model, and the base
185
+ `Phonemizer` keeps punctuation.
186
+
187
+ Each step follows the same shape:
188
+ ```cpp
189
+ phonemes = lookup_stem_s(token.text, tag, stress);
190
+ if (!phonemes.empty()) {
191
+ return std::make_optional(phonemes);
192
+ }
193
+ ```
194
+
195
+ ### 2.2 Two ways to say "not found", by layer
196
+ - At the interface boundary, `Phonemizer::phonemize(const Token&)` returns
197
+ `std::optional<std::u32string>`, and `std::nullopt` means "cannot phonemize".
198
+ - Internal helpers (`lookup*`) return `std::u32string`, where an empty `U""` means "not found".
199
+ This keeps chains cheap. Convert to an optional only at the boundary.
200
+ - `std::optional<stress::Level>` means "leave stress unchanged" when empty, and
201
+ `std::optional<bool>` is used deliberately as a three-way value (`vowel_next`: vowel,
202
+ consonant, or unknown).
203
+
204
+ ### 2.3 Lookups relax the context step by step
205
+ - Lexicon keys are `"word"` or `"word|context"`, where the context is the part-of-speech tag.
206
+ - `lookup(word, tag)` tries the exact tag, then the parent tag (`get_parent_tag`: `VB*` → `VERB`,
207
+ `NN*` → `NOUN`, …), then no context.
208
+ - Case also relaxes: exact case first, then lowercase (`is_known(word, try_lowercase = true)`).
209
+
210
+ ### 2.4 Morphology is a stem lookup plus a phonological suffix rule
211
+ - First guard on length and suffix. Then an `if / else if` ladder finds a known stem. Then the stem
212
+ is phonemized, and a suffix allophone is chosen from its **last phoneme**.
213
+ - The small phoneme sets used for that choice are `static const std::u32string` locals tested with
214
+ `.find(c) != npos`:
215
+ ```cpp
216
+ // https://en.wiktionary.org/wiki/-s
217
+ static const std::u32string hard_s_suffixes = U"ptkfθ";
218
+ static const std::u32string soft_s_suffixes = U"szʃʒʧʤ";
219
+ if (hard_s_suffixes.find(phonemes.back()) != std::u32string::npos) {
220
+ return phonemes + U"s";
221
+ }
222
+ ```
223
+ - Dialect differences are a member flag set in the constructor (`british_(config.lang == "en-gb")`)
224
+ and resolved inline: `british_ ? U"ɪ" : U"ᵻ"`.
225
+ - IPA literals used only once stay inline (`U"ɾᵻd"`, `U"ɐm"`). They move to `constants.h` only
226
+ when shared or language-configurable.
227
+
228
+ ### 2.5 Lookahead context
229
+ - `update_context(curr_token_id, tokens)` fills a member `GlobalContext` before each token:
230
+ - `vowel_next`: whether the next word starts with a vowel.
231
+ - `future_to`: scans the next 2 tokens that are not punctuation for "to".
232
+ - `phonemize` stays `const` and only reads the context.
233
+
234
+ ### 2.6 Tokenization driven by rule tables
235
+ - The input is split into phrases on whitespace.
236
+ - **Hard** separators (non-alphanumeric characters with no rule) always split and become their own
237
+ tokens.
238
+ - **Soft** separators (keys in `split::Rules`) are resolved by their `Rule` in the recursive
239
+ `process_chunk`.
240
+ - `split::Exceptions` (matched case-insensitively) stop any further splitting.
241
+ - Scanning avoids copies. The buffer is an `(offset, len)` pair into the input, handed on as
242
+ `std::u32string_view` sub-views. Only the final tokens are copied into `std::u32string`.
243
+ - Assumptions about earlier stages are stated rather than re-checked:
244
+ `// We assume the input got preprocessed in a correct way (i.e. with TrimLayer)`.
245
+
246
+ ### 2.7 num2word: scan → classify → verbalize
247
+ - The scanner finds a number at a word boundary and classifies it as a `Mode`. It then builds
248
+ `StringifiedNumber{text, mode}` and calls `verbalize`, which parses the text and dispatches to
249
+ the virtual primitives.
250
+ - Each language's decimal separator is first normalised to `.`, so a single scanner works for every
251
+ language.
252
+ - Languages override the primitives. They override `verbalize` itself only for grammar quirks
253
+ (for example, Spanish "de" in dates).
254
+
255
+ ### 2.8 Punctuation and whitespace are kept by structure
256
+ - The base `Phonemizer::phonemize` appends:
257
+ - the phonemes;
258
+ - the raw punctuation character when the token was not phonemized (except a soft `.` or `-` in
259
+ the middle of a word);
260
+ - `' '` when `token.whitespace` is set.
261
+ - Output spacing therefore matches token boundaries.
262
+
263
+ ---
264
+
265
+ ## 3. Code organisation
266
+
267
+ ```
268
+ base/<module>/
269
+ config.h // struct Config
270
+ types.h // enums, aliases, small structs
271
+ constants.h // inline tables in <module>::constants
272
+ <module>.h/.cpp // interface / abstract base with the driver
273
+ <impl>_<module>.h/.cpp // concrete: lexicon_phonemizer, hmm_tagger
274
+ base/processor/<layer>/
275
+ layer.h/.cpp // one directory per layer: trim, sanitizer, term2word, num2word, sym2word
276
+ lang/<code>/
277
+ constants.h pipeline.h (header-only) num2word.h/.cpp [lexicon_phonemizer|hmm_tagger|stress].h/.cpp
278
+ ```
279
+ - One responsibility per file; a file is named after its main class or concept (snake_case).
280
+ - These are header-only:
281
+ - Language pipelines (an explicit decision: "Make lang-specific pipelines header only").
282
+ - Templates (`HybridPhonemizer`, `strings.h`, tensors).
283
+ - `constexpr` Unicode helpers.
284
+
285
+ Non-template logic of real size goes in a `.cpp`.
286
+ - Namespaces mirror directories, **but `base/` is not a namespace level**:
287
+ - `base/tokenizer` → `phonemis::tokenizer`
288
+ - `base/phonemizer/nn` → `phonemis::phonemizer::nn`
289
+ - `lang/en` → `phonemis::en`
290
+ - `utils/strings.h` → `phonemis::utils::strings`
291
+ - Use nested namespace syntax: `namespace phonemis::phonemizer::nn {`. Always close with the full
292
+ name: `} // namespace phonemis::phonemizer::nn`.
293
+ - Constants live in `<ns>::constants`, split by which code consumes them: `constants::num2word`,
294
+ `constants::tokenizer`, `constants::alphabet`, `constants::ipa`, `constants::puncts`,
295
+ `constants::sanitizer`, `constants::ipa::stress`.
296
+ - In language `constants.h` files, each block opens with a banner such as
297
+ `// --- Tokenization Rules ---`.
298
+ - The **contents of the nested namespace are indented by 2**, and the block closes with
299
+ `} // namespace tokenizer`.
300
+ - Base types are imported with a fully qualified, leading-`::` using-declaration:
301
+ `using ::phonemis::tokenizer::split::Rule;`.
302
+ - File-local helpers go in an anonymous namespace at the top of the `.cpp`
303
+ (`// Helper functions` / `} // namespace`).
304
+ - Use `#pragma once` (not include guards).
305
+
306
+ **Include order**
307
+ ```cpp
308
+ #include "constants.h" // 1. local, quoted, alphabetical (own header not forced first)
309
+ #include "lexicon_phonemizer.h"
310
+ #include "stress.h"
311
+ #include <phonemis/base/phonemizer/constants.h> // 2. project headers, <phonemis/...> path from src/
312
+ #include <phonemis/utils/strings.h>
313
+
314
+ #include <algorithm> // 3. standard library, alphabetical
315
+ #include <string>
316
+
317
+ #ifdef ET_ON // 4. backend / conditional includes last
318
+ ```
319
+ - Inside `base/`, sibling modules are included by relative path (`"../tokenizer/token.h"`,
320
+ `"../types.h"`).
321
+ - Crossing into `utils/`, `lang/` or `protophone/` uses `<phonemis/...>`.
322
+ - Third-party headers use `<third-party/json.hpp>`.
323
+
324
+ ---
325
+
326
+ ## 4. Naming
327
+
328
+ | Entity | Convention | Examples |
329
+ |---|---|---|
330
+ | Classes / structs | PascalCase; acronyms stay upper case | `LexiconPhonemizer`, `TensorView`, `HMMTagger`, `GlobalContext` |
331
+ | Interfaces | `I` prefix only on the top-level pipeline interface | `IPipeline`; other abstract bases have no prefix (`Phonemizer`, `Tagger`, `Layer`) |
332
+ | Functions, methods, locals, params | snake_case | `update_context`, `lookup_stem_ing`, `curr_token_id`, `token_vec` |
333
+ | Non-public data members | snake_case + trailing `_` | `dict_`, `rules_`, `impl_`, `british_`, `global_context_` |
334
+ | Public struct fields | snake_case, no suffix | `text`, `whitespace`, `lexicon_filepath`, `phoneme_offset` |
335
+ | Constants | `k` + PascalCase, `inline const` / `inline constexpr` | `kPrimary`, `kEosCharacters`, `kSpecialCharacters`, `kCardinals` |
336
+ | Enumerators | SCREAMING_SNAKE | `KEEP_WITH_RIGHT`, `POTENTIALLY_ORDINAL`, `EMPHASIZED` |
337
+ | Type aliases | PascalCase domain words, even for trivial aliases | `using Lang = std::string;`, `using Tag = std::string;`, `Filter`, `Mapper`, `Rules`, `Exceptions`, `Buffer` |
338
+ | Template params | short | `T`, `U`, `StringT`, `CharT`, `Pred`, `LXP`, `NNP` |
339
+ | Macros | SCREAMING_SNAKE | `MAKE_NON_INPLACE`, `REGISTER_TEST`, `ET_ON` |
340
+
341
+ - **In-place (mutating) string operations end in `__`**: `to_lower__`, `remove__`, `replace__`,
342
+ `filter__`. The non-mutating version has the plain name and is generated by
343
+ `MAKE_NON_INPLACE(name)`.
344
+ - The string utilities borrow Python's vocabulary: `strip`, `split`, `capitalize`, `is_alpha`,
345
+ `starts_with`, `ends_with`.
346
+ - Predicates start with `is_`, `has_` or `should_` (`is_known`, `is_soft_separator`,
347
+ `has_primary`, `should_lowercase`). Boolean flags are adjectives or nouns: `british_`, `first`,
348
+ `whitespace`, `vowel_next`, `future_to`, `last_was_space`.
349
+ - Variants of one operation share a stem and add a suffix: `lookup`, `lookup_and_restress`,
350
+ `lookup_stem_s|_ed|_ing`, `lookup_nnp`, `lookup_special`.
351
+ - Short or abbreviated local names are normal:
352
+ - `currw_offset` / `currw_len` (current word)
353
+ - `fp` (file path)
354
+ - `bpoint`, `lbound` / `rbound`
355
+ - `no_steps` / `no_classes` ("number of")
356
+ - `p1` / `p2` / `p3`, `dec_sep`, `idx`, `it`
357
+ - Prefixes and suffixes carry meaning:
358
+ - `nn_` marks neural-network config fields (`nn_model_filepath`).
359
+ - `*_filepath` marks paths.
360
+ - Converted copies are named after what they are: `utf8_text`, `lower_word`, `word_stripped`,
361
+ `word_without_dots`.
362
+ - Legacy: `nn/constants.h` uses SCREAMING constants (`MAX_SEQ_LEN`, `PAD_TOKEN`,
363
+ `DEFAULT_CHAR_TO_TOKEN`). New constants should use `kPascalCase`.
364
+
365
+ ---
366
+
367
+ ## 5. Formatting
368
+
369
+ - **Indentation: 2 spaces.** This is the dominant style; use it for new code. Some legacy files use
370
+ tabs (`tokenizer.cpp/.h`, base `lexicon_phonemizer.cpp`, `io.cpp`, `strings.h`) or 4 spaces
371
+ (`nn/tokenizer.h`, `num2word/layer.h`, `lang/*/num2word.h`, `main.cpp`, tests). When editing
372
+ those, match the surrounding lines.
373
+ - Braces are attached (K&R) for functions, classes and control flow. `public:` / `protected:` /
374
+ `private:` line up with `class`.
375
+ - Short guard clauses can be one line without braces: `if (chunk.empty()) return;`,
376
+ `if (t == 0) break;`, `if (!val) return U"";`. Everything else gets braces.
377
+ - When every branch of an `else if` ladder has its own comment, `}` goes on its own line and
378
+ `else if (...)` starts the next one (see `stress::apply`, `lookup_stem_ed`). Otherwise use
379
+ `} else if (...) {`.
380
+ - Long conditions break after `&&` or `||` and align with the opening parenthesis. Long parameter
381
+ lists are wrapped and aligned to the first parameter.
382
+ - `&` and `*` attach to the type: `const Config& config`, `T* data_`.
383
+ - Constructor initializer lists start on the next line with an indented `: `, one member per line
384
+ when they are long.
385
+ - Lookup tables are aligned in columns and pack several entries per line. Trailing comments in
386
+ structs are aligned too:
387
+ ```cpp
388
+ bool first = false; // True if it's the first token in a sentence.
389
+ bool whitespace = false; // True if there is trailing whitespace implicitly included.
390
+ ```
391
+ - Leave a blank line after the opening `namespace …{` line and before the closing one. Inside a
392
+ function, logical blocks are separated by a blank line plus a comment.
393
+ - There is no hard column limit; lines of about 120–130 characters are common.
394
+
395
+ ---
396
+
397
+ ## 6. Comments and documentation
398
+
399
+ - **Public API in headers** uses Javadoc-style `/** … */` with `@param`, `@returns` / `@return`,
400
+ `@details`, `@throws`, `@tparam` and `@ref`.
401
+ - The first sentence is brief and the details follow.
402
+ - Parameter descriptions are short, often lowercase, often with an article:
403
+ `@param text an input text (utf-8) to be processed.`
404
+ - Simple members get a single `//` line, or nothing:
405
+ `// Performs a preprocessing stage of the pipeline.`. Groups of overrides sit under
406
+ `// Base class overrides`.
407
+ - **Voice:**
408
+ - Descriptions often start with an article: "A lexicon based phonemizer, which utilizes …",
409
+ "A shortcut for base class calls", "A (word | context) -> phonemes mapping.", "An interface
410
+ which allows to dynamically resolve pipelines …".
411
+ - Rationale and assumptions use "we": "We store both keys and values as utf-8 strings to save
412
+ memory comparing to u32string keys".
413
+ - Comments are short (1–3 lines), practical and candid: `// A hack to omit the leading
414
+ whitespaces`, `// Heuristic allocation`, `// WARNING: This file is called 'big szpont'`.
415
+ - `// NOTE:` marks behavioural caveats.
416
+ - **Numbered steps** in algorithms and setup code:
417
+ - `// 1. Context Update`, `// 2. Core Phonemization`, `// 3. Fallback/Punctuation Logic`,
418
+ `// 4. Whitespace handling`
419
+ - `// Step 0: Initialization`
420
+ - Pipelines: `// 1. Setup Preprocessing layers`, `// 2. Setup PoS tagger if specified`;
421
+ `// 1. Tokenize`, `// 2. Apply Part-of-Speech tags`,
422
+ `// 3. Generate phonemes (Lexicon with Neural fallback)`.
423
+ - **Examples inside comments:** `// xyz'abc -> xyz, 'abc (if xyz not empty)`,
424
+ `// '110xxxxx' pattern`, `(e.g., "it'", "s")`.
425
+ - External references are bare URLs: `// https://en.wiktionary.org/wiki/-ed`.
426
+ - Non-ASCII literals are annotated with a name and code point:
427
+ `U'।', // Hindi Purna Viram (U+0964)`.
428
+ - **Section banners:**
429
+ - utilities: `// ----------------------` / `// ----- Predicates -----` / `// ----------------------`
430
+ - language constants: `// --- Number to Word Normalization ---`
431
+ - long class bodies: `// ---- Weight loading ----…`
432
+ - Utility headers have a doc block above the namespace describing the whole module
433
+ (`/** Type conversions … */`,
434
+ `/** String utilities. … NOTE: Inline (mutable) versions … trailing __. */`).
435
+ - In dense declaration lists, end-of-line comments describe each item: the `lookup_*`
436
+ declarations in `en/lexicon_phonemizer.h`, and buffer shapes in protophone (`// S x L`).
437
+
438
+ ---
439
+
440
+ ## 7. C++ idioms and technical choices
441
+
442
+ - **C++20, used where it helps:**
443
+ - concepts (`std::derived_from`), `std::span`, `contains()`
444
+ - designated initializers (`{.data_filepath = argv[++i]}`)
445
+ - structured bindings (`for (const auto& [key, value] : json_obj.items())`)
446
+ - `if` with an initializer (`if (auto it = m.find(c); it != m.end())`)
447
+ - `if constexpr`, and CTAD (`std::basic_string_view suffix_view{suffix}`)
448
+ - Algorithms: the author's own code mostly uses classic iterator pairs (`std::find_if`,
449
+ `std::any_of(begin, end, …)`) plus some `std::ranges::*`. Both are fine.
450
+ - **Text model: UTF-32 inside, UTF-8 at the edges.**
451
+ - Internal text is `std::u32string`, `std::u32string_view`, `char32_t`, `U'x'` and `U"…"`.
452
+ - UTF-8 appears only in the public API overloads, JSON loading and lexicon storage.
453
+ Dictionaries store UTF-8 keys and values to save memory and convert on lookup.
454
+ - **No dependencies:**
455
+ - Unicode handling is in-house: a lookup table (`unicode_table.h`) plus `constexpr inline`
456
+ predicates (`unicode::isalpha`, `tolower`, …), not `<locale>`.
457
+ - Generic helpers use a paired `using` so the same code works for `char` and `char32_t`:
458
+ `using std::isalpha; using unicode::isalpha;`.
459
+ - **Parameter passing:**
460
+ - `std::u32string_view` for read-only text.
461
+ - `const std::u32string&` when the callee needs a real string (map keys, `substr` plus
462
+ concatenation).
463
+ - `std::span<const Token>` vs `std::span<Token>` to signal read-only vs in-place.
464
+ - Small types by value. Return values by value.
465
+ - **Ownership:**
466
+ - Value members for parts that are always present.
467
+ - `std::unique_ptr<T> x_ = nullptr` (created with `std::make_unique`) for optional or
468
+ polymorphic parts.
469
+ - Raw `const T*` for static tables owned elsewhere, always null-checked
470
+ (`rules_ && rules_->contains(c)`).
471
+ - **Class hygiene:** `explicit` on one-argument constructors, `virtual ~Base() = default;`,
472
+ `override` on every override, `= default` where possible, and `const` on every query method.
473
+ - **Constants:**
474
+ - Tables are `inline const` containers in headers: `std::unordered_map` / `unordered_set`;
475
+ `std::map` where order matters (number scales); `std::vector` for index-addressed lists
476
+ (months, with `U""` at index 0); `std::array` for fixed-size sets.
477
+ - Scalars use `inline constexpr`.
478
+ - A constant derived from another is built with an immediately invoked lambda:
479
+ ```cpp
480
+ inline const std::unordered_set<char32_t> kPunctuations = [] {
481
+ auto s = kNonQuotePunctations;
482
+ s.insert(U'"');
483
+ return s;
484
+ }();
485
+ ```
486
+ - A small lookup string used in one function is a function-local `static const`.
487
+ - **Optionals:** `has_value()` / `value()` and `*opt` are both used. `value_or("")` supplies
488
+ defaults, and returns write `std::make_optional(...)` explicitly.
489
+ - **Performance defaults for mobile/edge CPUs:**
490
+ - `reserve()` with a rough size before loops (`tokens.size() * 5 // Heuristic allocation`,
491
+ `input.size() / 5`).
492
+ - Offset-and-length views instead of substring copies.
493
+ - Flat vectors and dense ids on hot paths.
494
+ - SIMD-aligned allocators and scratch buffers that only grow, in the neural engine.
495
+ - **`using`:**
496
+ - A `.cpp` may start with `using namespace utils;` inside the project namespace, then call
497
+ `strings::…`, `conversions::…`, `unicode::…`.
498
+ - Functions that use many constants add a function-scope `using namespace …::constants;` or a
499
+ targeted `using …::kPrimary;`.
500
+ - Headers only have targeted declarations (`using tokenizer::Token;`, `using tagger::Tag;`).
501
+ - Small predicates are inline lambdas, often with an explicit `-> bool`.
502
+ - Casts are explicit `static_cast`, and indices are `size_t`.
503
+ - Unused parameters keep their names in comments: `size_t /*curr_token_id*/`.
504
+ - Macros are used only to generate code (non-inplace wrappers, test registration).
505
+
506
+ ---
507
+
508
+ ## 8. Error handling and robustness
509
+
510
+ - **Throw only during construction and resource loading:**
511
+ - A missing required config throws `std::runtime_error`, formatted as
512
+ `"<Class>: <field> must be provided in the configuration."`.
513
+ - Bad arguments or malformed data throw `std::invalid_argument` (unsupported language, invalid
514
+ JSON, wrong value type in the lexicon or tokenizer JSON).
515
+ - I/O failures throw `std::runtime_error`.
516
+ - Validate once at load time, then trust the data on the hot path. For example, the lexicon is
517
+ checked to be string → string in the constructor.
518
+ - **Phonemization never throws:**
519
+ - An unknown word gives `std::nullopt` or `U""`, and the next fallback takes over.
520
+ - Characters not in the tokenizer mapping are skipped silently, with a `// NOTE:` saying so.
521
+ - Words that are too long are split recursively.
522
+ - Invalid UTF-8 bytes become U+FFFD.
523
+ - Exceptions are caught only at the outermost layer (`main.cpp`), or around third-party parsing,
524
+ where they are rethrown as `std::invalid_argument` with context added.
525
+
526
+ ---
527
+
528
+ ## 9. Not the author's voice: do not imitate
529
+
530
+ These patterns are in the tree but come from the external refactor (`c8d8744`, `36cef09`) or from
531
+ the AI-generated num2word code:
532
+ - Paragraph-long rationale comments on members. Examples: `token_to_char_` in `nn/tokenizer.h`,
533
+ the probability tables in `tagger/hmm_tagger.h`, and `phonemize_words` in `ipipeline.cpp`.
534
+ - Phrases such as "matching the previous behaviour", "mirroring the original behavior", "hot path",
535
+ "pure scanning: it does not mutate any state".
536
+ - Em dashes (—) and textbook grammar explanations in comments (non-English `constants.h`).
537
+ - Helpers split out for a single condition (`at_word_end`, `is_trailing_currency`).
538
+
539
+ The author's own version of these is a 1–3 line comment saying what the code does (and briefly
540
+ why), numbered steps, and an inline example.
541
+
542
+ ---
543
+
544
+ ## 10. Known inconsistencies
545
+
546
+ Use the dominant form in new code. Do not "fix" these in unrelated changes.
547
+ - Indentation: 2 spaces dominant; tabs and 4 spaces in legacy files.
548
+ - Constant naming: `kName` dominant; SCREAMING in `nn/constants.h` and `LOG_EPSILON`.
549
+ - Some closing namespace comments are stale (`} // namespace phonemis::tagger::constants` in
550
+ `tokenizer/constants.h`, `} // namespace phonemis::utilities::conversions`, `} // phonemis::en`).
551
+ Always write the correct full name.
552
+ - `@return` and `@returns` are both used. Some `@param` names are stale (`tokenVec` vs `token_vec`).
553
+ - `i++` and `++i` are both used. Many files have no trailing newline at EOF.
554
+
555
+ ---
556
+
557
+ ## 11. Checklists
558
+
559
+ ### Adding a language `xx`
560
+ 1. Create `lang/xx/constants.h`, using `namespace phonemis::xx::constants`:
561
+ - `// --- Number to Word Normalization ---` → `namespace num2word { kCardinals, kLargeCardinals (std::map), kCurrencies, kMonths (index 0 = U""), kOrdinalSuffixes }`
562
+ - `// --- Tokenization Rules ---` → `namespace tokenizer { using ::phonemis::tokenizer::split::Rule; using …::Exceptions; kSpecialCharacters; kExceptions }`
563
+ 2. Create `lang/xx/num2word.h/.cpp`:
564
+ - Declare `class Num2Word : public processor::num2word::Num2WordLayer` with
565
+ `using Num2WordLayer::Num2WordLayer;`.
566
+ - Define `decimal_separator()` inline in the header.
567
+ - Declare the remaining primitives with `override`.
568
+ 3. Create a header-only `lang/xx/pipeline.h` following this skeleton:
569
+ ```cpp
570
+ namespace phonemis::xx {
571
+
572
+ class Pipeline : public IPipeline {
573
+ public:
574
+ explicit Pipeline(const Config& config)
575
+ : tokenizer_(&constants::tokenizer::kSpecialCharacters,
576
+ &constants::tokenizer::kExceptions),
577
+ phonemizer_(config.phonemizer) {
578
+
579
+ // 1. Setup Preprocessing layers
580
+ preprocessor_.add_layer(std::make_unique<processor::trim::TrimLayer>());
581
+ preprocessor_.add_layer(std::make_unique<Num2Word>());
582
+ }
583
+
584
+ // Performs a preprocessing stage of the pipeline.
585
+ std::u32string preprocess(const std::u32string& input) override {
586
+ return preprocessor_.process(input);
587
+ }
588
+
589
+ // Performs a middle stage of the pipeline - including phonemization.
590
+ std::u32string process(const std::u32string& input) override {
591
+ // 1. Tokenize
592
+ auto tokens = tokenizer_.tokenize(input);
593
+
594
+ // 2. Generate phonemes (Lexicon with Neural fallback)
595
+ return phonemizer_.phonemize(tokens);
596
+ }
597
+
598
+ // Performs a postprocessing stage of the pipeline.
599
+ std::u32string postprocess(const std::u32string& input) override {
600
+ // No postprocessing
601
+ return input;
602
+ }
603
+
604
+ private:
605
+ // Required submodules
606
+ processor::Preprocessor preprocessor_;
607
+ tokenizer::Tokenizer tokenizer_;
608
+ phonemizer::HybridPhonemizer<phonemizer::LexiconPhonemizer, phonemizer::nn::NeuralPhonemizer> phonemizer_;
609
+ };
610
+
611
+ } // namespace phonemis::xx
612
+ ```
613
+ 4. Register the language in `base/pipeline.cpp`: add `#include <phonemis/lang/xx/pipeline.h>` and
614
+ `if (config.lang == "xx") { // Name` returning `std::make_unique<xx::Pipeline>(config)`.
615
+ 5. Put data in `data/xx/`, and add tests (`test/num2word_xx_test.cpp`, …).
616
+
617
+ ### Adding a component to `base/`
618
+ - Write an abstract base whose non-virtual driver loops over units and calls a pure virtual,
619
+ `const` per-unit hook. Add `virtual ~X() = default;`.
620
+ - Put `struct Config` in `config.h`. Document every field; optional resources are
621
+ `std::optional<std::string> …_filepath = std::nullopt`, and a missing one disables the feature.
622
+ - Write the concrete implementation as `<impl>_<component>.h/.cpp` with
623
+ `explicit X(const Config& config);`. The constructor throws if a required config value is
624
+ missing and validates loaded data once.
625
+ - Put tables in `constants.h` (`kName`, `inline const`), and enums and aliases in `types.h`.
626
+ - Plug the component into the language pipelines as a value member if required, or as a
627
+ `unique_ptr` (`= nullptr`) if optional.
628
+
629
+ ---
630
+
631
+ ## Appendix: tests (`test/`)
632
+ - The harness is in-house and has no dependencies (`test/test.h`).
633
+ - `REGISTER_TEST(name) { …; return true; }` defines a test.
634
+ - `ASSERT_EQUALS(expected, real)` prints a coloured message with file and line, then returns
635
+ `false`.
636
+ - A single runner lives in `test/test.cpp`.
637
+ - There is one file per component and variant, named `<component>_<base|lang>_test.cpp`
638
+ (`tokenizer_base_test.cpp`, `num2word_pl_test.cpp`).
639
+ - Test names follow `<component>_<variant>_<scenario>_test`
640
+ (`tokenizer_base_basic_tokenization_test`).
641
+ - Test code is older and formatted differently: 4-space indent, function braces on a new line, and
642
+ helper wrapper structs with `operator==` / `operator<<` for readable failures.