@delali/narsil-react-native 0.3.1-next.155 → 0.3.1-next.156

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 (253) hide show
  1. package/NOTICE +144 -0
  2. package/NarsilReactNative.podspec +2 -2
  3. package/android/CMakeLists.txt +1 -1
  4. package/cpp/HybridNarsilCoreAnalysis.cpp +277 -0
  5. package/cpp/HybridNarsilCoreImpl.hpp +43 -0
  6. package/cpp/HybridNarsilCoreKeyword.cpp +253 -0
  7. package/cpp/HybridNarsilCoreMath.cpp +47 -0
  8. package/cpp/core/include/narsil_analysis.h +86 -0
  9. package/cpp/core/include/narsil_core.h +1 -1
  10. package/cpp/core/include/narsil_keyword.h +110 -0
  11. package/cpp/core/include/narsil_math.h +36 -0
  12. package/cpp/core/src/analysis/analyse.c +281 -0
  13. package/cpp/core/src/analysis/analyser.h +49 -0
  14. package/cpp/core/src/analysis/languages.c +79 -0
  15. package/cpp/core/src/analysis/languages.h +42 -0
  16. package/cpp/core/src/analysis/normalise.c +242 -0
  17. package/cpp/core/src/analysis/normalise.h +28 -0
  18. package/cpp/core/src/analysis/split.c +183 -0
  19. package/cpp/core/src/analysis/split.h +27 -0
  20. package/cpp/core/src/analysis/stop_words.c +82 -0
  21. package/cpp/core/src/analysis/stop_words.h +19 -0
  22. package/cpp/core/src/analysis/term_cache.c +88 -0
  23. package/cpp/core/src/analysis/term_cache.h +36 -0
  24. package/cpp/core/src/analysis/text.c +161 -0
  25. package/cpp/core/src/analysis/text.h +45 -0
  26. package/cpp/core/src/analysis/transform.c +103 -0
  27. package/cpp/core/src/analysis/unicode.c +252 -0
  28. package/cpp/core/src/analysis/unicode.h +54 -0
  29. package/cpp/core/src/internal.h +4 -0
  30. package/cpp/core/src/keyword/pass.h +117 -0
  31. package/cpp/core/src/keyword/prune.c +324 -0
  32. package/cpp/core/src/keyword/request.c +179 -0
  33. package/cpp/core/src/keyword/rows.c +83 -0
  34. package/cpp/core/src/keyword/rows.h +18 -0
  35. package/cpp/core/src/keyword/score.c +257 -0
  36. package/cpp/core/src/keyword/score.h +17 -0
  37. package/cpp/core/src/keyword/scratch.c +226 -0
  38. package/cpp/core/src/keyword/scratch.h +55 -0
  39. package/cpp/core/src/keyword/select.c +155 -0
  40. package/cpp/core/src/keyword/select.h +17 -0
  41. package/cpp/core/src/languages/bulgarian_stemmer.c +114 -0
  42. package/cpp/core/src/languages/data/albanian.c +54 -0
  43. package/cpp/core/src/languages/data/amharic.c +93 -0
  44. package/cpp/core/src/languages/data/arabic.c +146 -0
  45. package/cpp/core/src/languages/data/armenian.c +46 -0
  46. package/cpp/core/src/languages/data/azerbaijani.c +68 -0
  47. package/cpp/core/src/languages/data/bambara.c +48 -0
  48. package/cpp/core/src/languages/data/basque.c +62 -0
  49. package/cpp/core/src/languages/data/belarusian.c +56 -0
  50. package/cpp/core/src/languages/data/bengali.c +63 -0
  51. package/cpp/core/src/languages/data/bosnian.c +73 -0
  52. package/cpp/core/src/languages/data/breton.c +52 -0
  53. package/cpp/core/src/languages/data/bulgarian.c +144 -0
  54. package/cpp/core/src/languages/data/burmese.c +48 -0
  55. package/cpp/core/src/languages/data/catalan.c +84 -0
  56. package/cpp/core/src/languages/data/chinese.c +70 -0
  57. package/cpp/core/src/languages/data/croatian.c +72 -0
  58. package/cpp/core/src/languages/data/czech.c +72 -0
  59. package/cpp/core/src/languages/data/dagbani.c +88 -0
  60. package/cpp/core/src/languages/data/danish.c +56 -0
  61. package/cpp/core/src/languages/data/declarations.h +114 -0
  62. package/cpp/core/src/languages/data/dutch.c +58 -0
  63. package/cpp/core/src/languages/data/english.c +172 -0
  64. package/cpp/core/src/languages/data/esperanto.c +71 -0
  65. package/cpp/core/src/languages/data/estonian.c +417 -0
  66. package/cpp/core/src/languages/data/ewe.c +89 -0
  67. package/cpp/core/src/languages/data/faroese.c +54 -0
  68. package/cpp/core/src/languages/data/fijian.c +44 -0
  69. package/cpp/core/src/languages/data/finnish.c +100 -0
  70. package/cpp/core/src/languages/data/french.c +74 -0
  71. package/cpp/core/src/languages/data/ga.c +83 -0
  72. package/cpp/core/src/languages/data/galician.c +70 -0
  73. package/cpp/core/src/languages/data/georgian.c +57 -0
  74. package/cpp/core/src/languages/data/german.c +96 -0
  75. package/cpp/core/src/languages/data/greek.c +202 -0
  76. package/cpp/core/src/languages/data/guarani.c +110 -0
  77. package/cpp/core/src/languages/data/gujarati.c +90 -0
  78. package/cpp/core/src/languages/data/haitian-creole.c +54 -0
  79. package/cpp/core/src/languages/data/hausa.c +85 -0
  80. package/cpp/core/src/languages/data/hawaiian.c +50 -0
  81. package/cpp/core/src/languages/data/hebrew.c +85 -0
  82. package/cpp/core/src/languages/data/hindi.c +91 -0
  83. package/cpp/core/src/languages/data/hungarian.c +98 -0
  84. package/cpp/core/src/languages/data/icelandic.c +73 -0
  85. package/cpp/core/src/languages/data/igbo.c +90 -0
  86. package/cpp/core/src/languages/data/indonesian.c +296 -0
  87. package/cpp/core/src/languages/data/irish.c +60 -0
  88. package/cpp/core/src/languages/data/italian.c +107 -0
  89. package/cpp/core/src/languages/data/japanese.c +52 -0
  90. package/cpp/core/src/languages/data/kannada.c +60 -0
  91. package/cpp/core/src/languages/data/kazakh.c +57 -0
  92. package/cpp/core/src/languages/data/khmer.c +71 -0
  93. package/cpp/core/src/languages/data/kinyarwanda.c +54 -0
  94. package/cpp/core/src/languages/data/kirundi.c +53 -0
  95. package/cpp/core/src/languages/data/korean.c +74 -0
  96. package/cpp/core/src/languages/data/kurmanji.c +43 -0
  97. package/cpp/core/src/languages/data/kyrgyz.c +65 -0
  98. package/cpp/core/src/languages/data/lao.c +46 -0
  99. package/cpp/core/src/languages/data/latin.c +46 -0
  100. package/cpp/core/src/languages/data/latvian.c +75 -0
  101. package/cpp/core/src/languages/data/lingala.c +88 -0
  102. package/cpp/core/src/languages/data/lithuanian.c +65 -0
  103. package/cpp/core/src/languages/data/luxembourgish.c +80 -0
  104. package/cpp/core/src/languages/data/macedonian.c +286 -0
  105. package/cpp/core/src/languages/data/malagasy.c +51 -0
  106. package/cpp/core/src/languages/data/malay.c +184 -0
  107. package/cpp/core/src/languages/data/malayalam.c +64 -0
  108. package/cpp/core/src/languages/data/maltese.c +102 -0
  109. package/cpp/core/src/languages/data/maori.c +52 -0
  110. package/cpp/core/src/languages/data/marathi.c +62 -0
  111. package/cpp/core/src/languages/data/nepali.c +72 -0
  112. package/cpp/core/src/languages/data/norwegian.c +74 -0
  113. package/cpp/core/src/languages/data/oromo.c +51 -0
  114. package/cpp/core/src/languages/data/persian.c +150 -0
  115. package/cpp/core/src/languages/data/polish.c +111 -0
  116. package/cpp/core/src/languages/data/portuguese.c +91 -0
  117. package/cpp/core/src/languages/data/punjabi.c +80 -0
  118. package/cpp/core/src/languages/data/registry.c +116 -0
  119. package/cpp/core/src/languages/data/romanian.c +93 -0
  120. package/cpp/core/src/languages/data/russian.c +76 -0
  121. package/cpp/core/src/languages/data/samoan.c +47 -0
  122. package/cpp/core/src/languages/data/sanskrit.c +53 -0
  123. package/cpp/core/src/languages/data/scottish-gaelic.c +119 -0
  124. package/cpp/core/src/languages/data/serbian.c +84 -0
  125. package/cpp/core/src/languages/data/shona.c +55 -0
  126. package/cpp/core/src/languages/data/sinhala.c +78 -0
  127. package/cpp/core/src/languages/data/slovak.c +135 -0
  128. package/cpp/core/src/languages/data/slovenian.c +139 -0
  129. package/cpp/core/src/languages/data/sorani.c +55 -0
  130. package/cpp/core/src/languages/data/spanish.c +84 -0
  131. package/cpp/core/src/languages/data/swahili.c +59 -0
  132. package/cpp/core/src/languages/data/swedish.c +60 -0
  133. package/cpp/core/src/languages/data/tagalog.c +75 -0
  134. package/cpp/core/src/languages/data/tamil.c +69 -0
  135. package/cpp/core/src/languages/data/tatar.c +548 -0
  136. package/cpp/core/src/languages/data/telugu.c +54 -0
  137. package/cpp/core/src/languages/data/thai.c +46 -0
  138. package/cpp/core/src/languages/data/tibetan.c +55 -0
  139. package/cpp/core/src/languages/data/tigrinya.c +73 -0
  140. package/cpp/core/src/languages/data/tongan.c +47 -0
  141. package/cpp/core/src/languages/data/turkish.c +100 -0
  142. package/cpp/core/src/languages/data/twi.c +88 -0
  143. package/cpp/core/src/languages/data/ukrainian.c +99 -0
  144. package/cpp/core/src/languages/data/urdu.c +174 -0
  145. package/cpp/core/src/languages/data/vietnamese.c +88 -0
  146. package/cpp/core/src/languages/data/welsh.c +143 -0
  147. package/cpp/core/src/languages/data/wolof.c +51 -0
  148. package/cpp/core/src/languages/data/xhosa.c +56 -0
  149. package/cpp/core/src/languages/data/yoruba.c +93 -0
  150. package/cpp/core/src/languages/data/zulu.c +58 -0
  151. package/cpp/core/src/languages/marks.c +64 -0
  152. package/cpp/core/src/languages/rules.c +63 -0
  153. package/cpp/core/src/languages/rules.h +68 -0
  154. package/cpp/core/src/languages/sanskrit_stemmer.c +50 -0
  155. package/cpp/core/src/languages/scripts.c +143 -0
  156. package/cpp/core/src/languages/slovenian_stemmer.c +46 -0
  157. package/cpp/core/src/languages/snowball/api.c +52 -0
  158. package/cpp/core/src/languages/snowball/api.h +43 -0
  159. package/cpp/core/src/languages/snowball/arabic_stemmer.c +1506 -0
  160. package/cpp/core/src/languages/snowball/arabic_stemmer.h +24 -0
  161. package/cpp/core/src/languages/snowball/armenian_stemmer.c +523 -0
  162. package/cpp/core/src/languages/snowball/armenian_stemmer.h +24 -0
  163. package/cpp/core/src/languages/snowball/basque_stemmer.c +1089 -0
  164. package/cpp/core/src/languages/snowball/basque_stemmer.h +24 -0
  165. package/cpp/core/src/languages/snowball/catalan_stemmer.c +1380 -0
  166. package/cpp/core/src/languages/snowball/catalan_stemmer.h +24 -0
  167. package/cpp/core/src/languages/snowball/czech_stemmer.c +582 -0
  168. package/cpp/core/src/languages/snowball/czech_stemmer.h +24 -0
  169. package/cpp/core/src/languages/snowball/danish_stemmer.c +352 -0
  170. package/cpp/core/src/languages/snowball/danish_stemmer.h +24 -0
  171. package/cpp/core/src/languages/snowball/dutch_stemmer.c +1657 -0
  172. package/cpp/core/src/languages/snowball/dutch_stemmer.h +24 -0
  173. package/cpp/core/src/languages/snowball/english_stemmer.c +1019 -0
  174. package/cpp/core/src/languages/snowball/english_stemmer.h +24 -0
  175. package/cpp/core/src/languages/snowball/esperanto_stemmer.c +716 -0
  176. package/cpp/core/src/languages/snowball/esperanto_stemmer.h +24 -0
  177. package/cpp/core/src/languages/snowball/estonian_stemmer.c +1361 -0
  178. package/cpp/core/src/languages/snowball/estonian_stemmer.h +24 -0
  179. package/cpp/core/src/languages/snowball/finnish_stemmer.c +800 -0
  180. package/cpp/core/src/languages/snowball/finnish_stemmer.h +24 -0
  181. package/cpp/core/src/languages/snowball/french_stemmer.c +1217 -0
  182. package/cpp/core/src/languages/snowball/french_stemmer.h +24 -0
  183. package/cpp/core/src/languages/snowball/german_stemmer.c +567 -0
  184. package/cpp/core/src/languages/snowball/german_stemmer.h +24 -0
  185. package/cpp/core/src/languages/snowball/greek_stemmer.c +3450 -0
  186. package/cpp/core/src/languages/snowball/greek_stemmer.h +24 -0
  187. package/cpp/core/src/languages/snowball/hindi_stemmer.c +325 -0
  188. package/cpp/core/src/languages/snowball/hindi_stemmer.h +24 -0
  189. package/cpp/core/src/languages/snowball/hungarian_stemmer.c +742 -0
  190. package/cpp/core/src/languages/snowball/hungarian_stemmer.h +24 -0
  191. package/cpp/core/src/languages/snowball/indonesian_stemmer.c +443 -0
  192. package/cpp/core/src/languages/snowball/indonesian_stemmer.h +24 -0
  193. package/cpp/core/src/languages/snowball/irish_stemmer.c +428 -0
  194. package/cpp/core/src/languages/snowball/irish_stemmer.h +24 -0
  195. package/cpp/core/src/languages/snowball/italian_stemmer.c +983 -0
  196. package/cpp/core/src/languages/snowball/italian_stemmer.h +24 -0
  197. package/cpp/core/src/languages/snowball/lithuanian_stemmer.c +794 -0
  198. package/cpp/core/src/languages/snowball/lithuanian_stemmer.h +24 -0
  199. package/cpp/core/src/languages/snowball/nepali_stemmer.c +361 -0
  200. package/cpp/core/src/languages/snowball/nepali_stemmer.h +24 -0
  201. package/cpp/core/src/languages/snowball/norwegian_stemmer.c +332 -0
  202. package/cpp/core/src/languages/snowball/norwegian_stemmer.h +24 -0
  203. package/cpp/core/src/languages/snowball/persian_stemmer.c +538 -0
  204. package/cpp/core/src/languages/snowball/persian_stemmer.h +24 -0
  205. package/cpp/core/src/languages/snowball/polish_stemmer.c +501 -0
  206. package/cpp/core/src/languages/snowball/polish_stemmer.h +24 -0
  207. package/cpp/core/src/languages/snowball/portuguese_stemmer.c +866 -0
  208. package/cpp/core/src/languages/snowball/portuguese_stemmer.h +24 -0
  209. package/cpp/core/src/languages/snowball/romanian_stemmer.c +940 -0
  210. package/cpp/core/src/languages/snowball/romanian_stemmer.h +24 -0
  211. package/cpp/core/src/languages/snowball/russian_stemmer.c +598 -0
  212. package/cpp/core/src/languages/snowball/russian_stemmer.h +24 -0
  213. package/cpp/core/src/languages/snowball/serbian_stemmer.c +6765 -0
  214. package/cpp/core/src/languages/snowball/serbian_stemmer.h +24 -0
  215. package/cpp/core/src/languages/snowball/snowball_runtime.h +122 -0
  216. package/cpp/core/src/languages/snowball/spanish_stemmer.c +955 -0
  217. package/cpp/core/src/languages/snowball/spanish_stemmer.h +24 -0
  218. package/cpp/core/src/languages/snowball/swedish_stemmer.c +364 -0
  219. package/cpp/core/src/languages/snowball/swedish_stemmer.h +24 -0
  220. package/cpp/core/src/languages/snowball/tamil_stemmer.c +1305 -0
  221. package/cpp/core/src/languages/snowball/tamil_stemmer.h +24 -0
  222. package/cpp/core/src/languages/snowball/turkish_stemmer.c +1700 -0
  223. package/cpp/core/src/languages/snowball/turkish_stemmer.h +24 -0
  224. package/cpp/core/src/languages/snowball/utilities.c +716 -0
  225. package/cpp/core/src/languages/substitutions.c +131 -0
  226. package/cpp/core/src/languages/swahili_stemmer.c +85 -0
  227. package/cpp/core/src/languages/ukrainian_stemmer.c +168 -0
  228. package/cpp/core/src/locks.c +2 -15
  229. package/cpp/core/src/math/apply.c +44 -0
  230. package/cpp/core/src/math/fdlibm.h +16 -0
  231. package/cpp/core/src/math/inverse.c +242 -0
  232. package/cpp/core/src/math/log.c +90 -0
  233. package/cpp/core/src/math/reduce.c +325 -0
  234. package/cpp/core/src/math/trig.c +188 -0
  235. package/cpp/core/src/math/words.h +45 -0
  236. package/cpp/core/src/thread_yield.h +18 -0
  237. package/cpp/core/src/unicode/decompositions.c +310 -0
  238. package/cpp/core/src/unicode/lowercase.c +172 -0
  239. package/cpp/core/src/unicode/properties.c +214 -0
  240. package/cpp/core/src/workspace.c +5 -1
  241. package/lib/engine/analysis.d.ts +3 -0
  242. package/lib/engine/analysis.js +76 -0
  243. package/lib/engine/core.js +5 -0
  244. package/lib/engine/keyword.d.ts +3 -0
  245. package/lib/engine/keyword.js +25 -0
  246. package/lib/specs/core.nitro.d.ts +1 -0
  247. package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.cpp +1 -0
  248. package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.hpp +1 -0
  249. package/package.json +4 -3
  250. package/src/engine/analysis.ts +87 -0
  251. package/src/engine/core.ts +6 -0
  252. package/src/engine/keyword.ts +26 -0
  253. package/src/specs/core.nitro.ts +1 -0
@@ -0,0 +1,242 @@
1
+ #include "normalise.h"
2
+
3
+ #include "../../include/narsil_core.h"
4
+ #include "text.h"
5
+ #include "unicode.h"
6
+
7
+ #include <stddef.h>
8
+ #include <stdint.h>
9
+
10
+ #define CAPITAL_SIGMA 0x3A3U
11
+ #define SMALL_FINAL_SIGMA 0x3C2U
12
+ #define ASCII_CAPITAL_A 0x41U
13
+ #define ASCII_CAPITAL_Z 0x5AU
14
+ #define ASCII_CASE_OFFSET 0x20U
15
+ #define APOSTROPHE 0x27U
16
+ #define LATIN_SMALL_I 0x69U
17
+ #define COMBINING_DOT_ABOVE 0x307U
18
+ #define DOTTED_CAPITAL_I 0x130U
19
+ #define ARMENIAN_MARKS_FIRST 0x55BU
20
+ #define ARMENIAN_MARKS_LAST 0x55FU
21
+ #define LEFT_SINGLE_QUOTE 0x2018U
22
+ #define RIGHT_SINGLE_QUOTE 0x2019U
23
+ #define MODIFIER_APOSTROPHE 0x2BCU
24
+ #define MODIFIER_TURNED_COMMA 0x2BBU
25
+ #define FULLWIDTH_ASCII_FIRST 0xFF01U
26
+ #define FULLWIDTH_ASCII_LAST 0xFF5EU
27
+ #define FULLWIDTH_ASCII_OFFSET 0xFEE0U
28
+ #define HALFWIDTH_KANA_FIRST 0xFF61U
29
+ #define HALFWIDTH_KANA_LAST 0xFF9DU
30
+ #define HALFWIDTH_VOICED_MARK 0xFF9EU
31
+ #define HALFWIDTH_SEMI_VOICED_MARK 0xFF9FU
32
+ #define COMBINING_VOICED_MARK 0x3099U
33
+ #define COMBINING_SEMI_VOICED_MARK 0x309AU
34
+ #define COMBINING_DIACRITICS_FIRST 0x300U
35
+ #define COMBINING_DIACRITICS_LAST 0x36FU
36
+ #define NON_STARTER_BEFORE_ANY_STARTER 256U
37
+
38
+ static const uint16_t halfwidth_kana_targets[HALFWIDTH_KANA_LAST - HALFWIDTH_KANA_FIRST + 1] = {
39
+ 0x3002, 0x300C, 0x300D, 0x3001, 0x30FB, 0x30F2, 0x30A1, 0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30E3, 0x30E5,
40
+ 0x30E7, 0x30C3, 0x30FC, 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3,
41
+ 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC,
42
+ 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E4,
43
+ 0x30E6, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F3,
44
+ };
45
+
46
+ void narsil_normalise_scratch_release(narsil_normalise_scratch *scratch) {
47
+ narsil_text_release(&scratch->first);
48
+ narsil_text_release(&scratch->second);
49
+ narsil_code_points_release(&scratch->points);
50
+ }
51
+
52
+ static void reorder_canonically(uint32_t *values, size_t length) {
53
+ for (size_t i = 1; i < length; i++) {
54
+ uint32_t value = values[i];
55
+ uint32_t value_class = narsil_unicode_combining_class(value);
56
+ if (value_class == 0) { continue; }
57
+ size_t position = i;
58
+ while (position > 0) {
59
+ uint32_t before_class = narsil_unicode_combining_class(values[position - 1]);
60
+ if (before_class <= value_class) { break; }
61
+ values[position] = values[position - 1];
62
+ position--;
63
+ }
64
+ values[position] = value;
65
+ }
66
+ }
67
+
68
+ static int decompose_text(const uint16_t *units, size_t length, narsil_code_points *points) {
69
+ points->length = 0;
70
+ int status = narsil_code_points_reserve(points, length);
71
+ if (status != NARSIL_OK) { return status; }
72
+ uint32_t parts[NARSIL_UNICODE_MAX_DECOMPOSITION];
73
+ size_t index = 0;
74
+ while (index < length) {
75
+ uint32_t count = narsil_unicode_decompose(narsil_decode_next(units, length, &index), parts);
76
+ for (uint32_t part = 0; part < count; part++) {
77
+ status = narsil_code_points_push(points, parts[part]);
78
+ if (status != NARSIL_OK) { return status; }
79
+ }
80
+ }
81
+ reorder_canonically(points->values, points->length);
82
+ return NARSIL_OK;
83
+ }
84
+
85
+ static size_t compose_in_place(uint32_t *values, size_t length) {
86
+ if (length == 0) { return 0; }
87
+ size_t starter_position = 0;
88
+ uint32_t starter = values[0];
89
+ uint32_t last_class = narsil_unicode_combining_class(starter);
90
+ if (last_class != 0) { last_class = NON_STARTER_BEFORE_ANY_STARTER; }
91
+ size_t kept = 1;
92
+ for (size_t i = 1; i < length; i++) {
93
+ uint32_t value = values[i];
94
+ uint32_t value_class = narsil_unicode_combining_class(value);
95
+ uint32_t composite = narsil_unicode_compose(starter, value);
96
+ if (composite != NARSIL_UNICODE_NO_COMPOSITE && (last_class < value_class || last_class == 0)) {
97
+ values[starter_position] = composite;
98
+ starter = composite;
99
+ continue;
100
+ }
101
+ if (value_class == 0) {
102
+ starter_position = kept;
103
+ starter = value;
104
+ }
105
+ last_class = value_class;
106
+ values[kept++] = value;
107
+ }
108
+ return kept;
109
+ }
110
+
111
+ static int encode_points(const uint32_t *values, size_t length, narsil_text *out) {
112
+ out->length = 0;
113
+ int status = narsil_text_reserve(out, length);
114
+ for (size_t i = 0; i < length && status == NARSIL_OK; i++) { status = narsil_text_push_code_point(out, values[i]); }
115
+ return status;
116
+ }
117
+
118
+ int narsil_nfd(const uint16_t *units, size_t length, narsil_text *out, narsil_code_points *points) {
119
+ int status = decompose_text(units, length, points);
120
+ if (status != NARSIL_OK) { return status; }
121
+ return encode_points(points->values, points->length, out);
122
+ }
123
+
124
+ int narsil_nfc(const uint16_t *units, size_t length, narsil_text *out, narsil_code_points *points) {
125
+ int status = decompose_text(units, length, points);
126
+ if (status != NARSIL_OK) { return status; }
127
+ points->length = compose_in_place(points->values, points->length);
128
+ return encode_points(points->values, points->length, out);
129
+ }
130
+
131
+ static int cased_letter_beside(const uint16_t *units, size_t length, size_t index, int forward) {
132
+ while (forward ? index < length : index > 0) {
133
+ uint32_t code_point = forward ? narsil_decode_next(units, length, &index) : narsil_decode_previous(units, &index);
134
+ uint32_t properties = narsil_unicode_properties(code_point);
135
+ if ((properties & NARSIL_UNICODE_CASE_IGNORABLE) != 0) { continue; }
136
+ return (properties & NARSIL_UNICODE_CASED) != 0;
137
+ }
138
+ return 0;
139
+ }
140
+
141
+ int narsil_lowercase(const uint16_t *units, size_t length, narsil_text *out) {
142
+ out->length = 0;
143
+ int status = narsil_text_reserve(out, length);
144
+ size_t index = 0;
145
+ while (index < length && status == NARSIL_OK) {
146
+ size_t start = index;
147
+ uint32_t code_point = narsil_decode_next(units, length, &index);
148
+ if (code_point == CAPITAL_SIGMA && cased_letter_beside(units, length, start, 0) &&
149
+ !cased_letter_beside(units, length, index, 1)) {
150
+ status = narsil_text_push(out, SMALL_FINAL_SIGMA);
151
+ continue;
152
+ }
153
+ uint32_t second = 0;
154
+ uint32_t lower = narsil_unicode_lowercase_of(code_point, &second);
155
+ status = narsil_text_push_code_point(out, lower);
156
+ if (status == NARSIL_OK && second != 0) { status = narsil_text_push_code_point(out, second); }
157
+ }
158
+ return status;
159
+ }
160
+
161
+ static uint16_t fold_width(uint16_t unit) {
162
+ if (unit >= FULLWIDTH_ASCII_FIRST && unit <= FULLWIDTH_ASCII_LAST) {
163
+ return (uint16_t)(unit - FULLWIDTH_ASCII_OFFSET);
164
+ }
165
+ if (unit >= HALFWIDTH_KANA_FIRST && unit <= HALFWIDTH_KANA_LAST) {
166
+ return halfwidth_kana_targets[unit - HALFWIDTH_KANA_FIRST];
167
+ }
168
+ if (unit == HALFWIDTH_VOICED_MARK) { return COMBINING_VOICED_MARK; }
169
+ if (unit == HALFWIDTH_SEMI_VOICED_MARK) { return COMBINING_SEMI_VOICED_MARK; }
170
+ return unit;
171
+ }
172
+
173
+ static int fold_forms(const narsil_text *source, narsil_text *out) {
174
+ out->length = 0;
175
+ int status = narsil_text_reserve(out, source->length);
176
+ for (size_t i = 0; i < source->length && status == NARSIL_OK; i++) {
177
+ uint16_t unit = source->units[i];
178
+ if (unit == COMBINING_DOT_ABOVE || (unit >= ARMENIAN_MARKS_FIRST && unit <= ARMENIAN_MARKS_LAST)) { continue; }
179
+ if (unit == DOTTED_CAPITAL_I) {
180
+ status = narsil_text_push(out, LATIN_SMALL_I);
181
+ } else if (unit == LEFT_SINGLE_QUOTE || unit == RIGHT_SINGLE_QUOTE || unit == MODIFIER_APOSTROPHE ||
182
+ unit == MODIFIER_TURNED_COMMA) {
183
+ status = narsil_text_push(out, APOSTROPHE);
184
+ } else {
185
+ status = narsil_text_push(out, unit);
186
+ }
187
+ }
188
+ return status;
189
+ }
190
+
191
+ int narsil_fold_for_splitting(const uint16_t *units, size_t length, narsil_text *out,
192
+ narsil_normalise_scratch *scratch) {
193
+ if (narsil_units_are_ascii(units, length)) {
194
+ out->length = 0;
195
+ int status = narsil_text_reserve(out, length);
196
+ if (status != NARSIL_OK) { return status; }
197
+ for (size_t i = 0; i < length; i++) {
198
+ uint16_t unit = units[i];
199
+ out->units[i] = unit >= ASCII_CAPITAL_A && unit <= ASCII_CAPITAL_Z ? (uint16_t)(unit + ASCII_CASE_OFFSET) : unit;
200
+ }
201
+ out->length = length;
202
+ return NARSIL_OK;
203
+ }
204
+ scratch->first.length = 0;
205
+ int status = narsil_text_reserve(&scratch->first, length);
206
+ if (status != NARSIL_OK) { return status; }
207
+ for (size_t i = 0; i < length; i++) { scratch->first.units[i] = fold_width(units[i]); }
208
+ scratch->first.length = length;
209
+ status = narsil_nfc(scratch->first.units, scratch->first.length, &scratch->second, &scratch->points);
210
+ if (status == NARSIL_OK) { status = fold_forms(&scratch->second, &scratch->first); }
211
+ if (status == NARSIL_OK) { status = narsil_lowercase(scratch->first.units, scratch->first.length, out); }
212
+ return status;
213
+ }
214
+
215
+ static int is_combining_diacritic(uint32_t code_point) {
216
+ return code_point >= COMBINING_DIACRITICS_FIRST && code_point <= COMBINING_DIACRITICS_LAST;
217
+ }
218
+
219
+ int narsil_strip_diacritics(const uint16_t *units, size_t length, narsil_text *out, narsil_code_points *points) {
220
+ int status = decompose_text(units, length, points);
221
+ if (status != NARSIL_OK) { return status; }
222
+ size_t kept = 0;
223
+ for (size_t i = 0; i < points->length; i++) {
224
+ if (!is_combining_diacritic(points->values[i])) { points->values[kept++] = points->values[i]; }
225
+ }
226
+ return encode_points(points->values, kept, out);
227
+ }
228
+
229
+ int narsil_remove_marks(const uint16_t *units, size_t length, narsil_mark_test is_removed, narsil_text *out,
230
+ narsil_normalise_scratch *scratch) {
231
+ if (narsil_units_are_ascii(units, length)) { return narsil_text_assign(out, units, length); }
232
+ int status = decompose_text(units, length, &scratch->points);
233
+ if (status != NARSIL_OK) { return status; }
234
+ size_t kept = 0;
235
+ for (size_t i = 0; i < scratch->points.length; i++) {
236
+ if (!is_removed(scratch->points.values[i])) { scratch->points.values[kept++] = scratch->points.values[i]; }
237
+ }
238
+ if (kept == scratch->points.length) { return narsil_text_assign(out, units, length); }
239
+ status = encode_points(scratch->points.values, kept, &scratch->first);
240
+ if (status != NARSIL_OK) { return status; }
241
+ return narsil_nfc(scratch->first.units, scratch->first.length, out, &scratch->points);
242
+ }
@@ -0,0 +1,28 @@
1
+ #ifndef NARSIL_ANALYSIS_NORMALISE_H
2
+ #define NARSIL_ANALYSIS_NORMALISE_H
3
+
4
+ #include "text.h"
5
+
6
+ #include <stddef.h>
7
+ #include <stdint.h>
8
+
9
+ typedef struct {
10
+ narsil_text first;
11
+ narsil_text second;
12
+ narsil_code_points points;
13
+ } narsil_normalise_scratch;
14
+
15
+ typedef int (*narsil_mark_test)(uint32_t code_point);
16
+
17
+ void narsil_normalise_scratch_release(narsil_normalise_scratch *scratch);
18
+
19
+ int narsil_nfd(const uint16_t *units, size_t length, narsil_text *out, narsil_code_points *points);
20
+ int narsil_nfc(const uint16_t *units, size_t length, narsil_text *out, narsil_code_points *points);
21
+ int narsil_lowercase(const uint16_t *units, size_t length, narsil_text *out);
22
+ int narsil_fold_for_splitting(const uint16_t *units, size_t length, narsil_text *out,
23
+ narsil_normalise_scratch *scratch);
24
+ int narsil_strip_diacritics(const uint16_t *units, size_t length, narsil_text *out, narsil_code_points *points);
25
+ int narsil_remove_marks(const uint16_t *units, size_t length, narsil_mark_test is_removed, narsil_text *out,
26
+ narsil_normalise_scratch *scratch);
27
+
28
+ #endif
@@ -0,0 +1,183 @@
1
+ #include "split.h"
2
+
3
+ #include "../../include/narsil_core.h"
4
+ #include "languages.h"
5
+ #include "text.h"
6
+ #include "unicode.h"
7
+
8
+ #include <stddef.h>
9
+ #include <stdint.h>
10
+ #include <stdlib.h>
11
+
12
+ #define MIN_SPANS 16U
13
+
14
+ #define PROLONGED_SOUND_MARK 0x30FCU
15
+ #define IDEOGRAPHIC_ITERATION_MARK 0x3005U
16
+ #define LOWEST_NGRAM_CODE_POINT 0x0E00U
17
+ #define LOWEST_MARK_CODE_POINT 0x0300U
18
+ #define THAI_BLOCK_END 0x0E7FU
19
+ #define LAO_BLOCK_END 0x0EFFU
20
+ #define MYANMAR_BLOCK_START 0x1000U
21
+ #define MYANMAR_BLOCK_END 0x109FU
22
+ #define KHMER_BLOCK_START 0x1780U
23
+ #define KHMER_BLOCK_END 0x19FFU
24
+ #define SOUTHEAST_ASIAN_BLOCKS_END 0x1A00U
25
+ #define HIRAGANA_BLOCK_START 0x3040U
26
+ #define HIRAGANA_BLOCK_END 0x309FU
27
+ #define COMBINING_VOICED_MARK 0x3099U
28
+ #define COMBINING_SEMI_VOICED_MARK 0x309AU
29
+ #define KATAKANA_BLOCK_START 0x30A0U
30
+ #define KATAKANA_BLOCK_END 0x30FFU
31
+ #define HAN_EXTENSION_A_START 0x3400U
32
+ #define HAN_EXTENSION_A_END 0x4DBFU
33
+ #define HAN_UNIFIED_START 0x4E00U
34
+ #define HAN_UNIFIED_END 0x9FFFU
35
+ #define HANGUL_SYLLABLE_START 0xAC00U
36
+ #define HANGUL_SYLLABLE_END 0xD7A3U
37
+ #define HAN_COMPATIBILITY_START 0xF900U
38
+ #define HAN_COMPATIBILITY_END 0xFAFFU
39
+
40
+ int narsil_spans_push(narsil_spans *spans, narsil_span span) {
41
+ if (spans->length >= spans->capacity) {
42
+ size_t capacity = spans->capacity < MIN_SPANS ? MIN_SPANS : spans->capacity;
43
+ while (capacity <= spans->length) {
44
+ if (capacity > (SIZE_MAX / sizeof(narsil_span)) / 2) { return NARSIL_OUT_OF_MEMORY; }
45
+ capacity *= 2;
46
+ }
47
+ narsil_span *grown = realloc(spans->spans, capacity * sizeof(narsil_span));
48
+ if (grown == NULL) { return NARSIL_OUT_OF_MEMORY; }
49
+ spans->spans = grown;
50
+ spans->capacity = capacity;
51
+ }
52
+ spans->spans[spans->length] = span;
53
+ spans->length++;
54
+ return NARSIL_OK;
55
+ }
56
+
57
+ static narsil_span span_of(size_t begin, size_t end) {
58
+ narsil_span span = {(uint32_t)begin, (uint32_t)(end - begin)};
59
+ return span;
60
+ }
61
+
62
+ void narsil_spans_release(narsil_spans *spans) {
63
+ free(spans->spans);
64
+ spans->spans = NULL;
65
+ spans->length = 0;
66
+ spans->capacity = 0;
67
+ }
68
+
69
+ static uint32_t next_split_unit(const narsil_language *language, const uint16_t *units, uint32_t length,
70
+ size_t *index) {
71
+ if (language->splits_code_points) { return narsil_decode_next(units, length, index); }
72
+ return units[(*index)++];
73
+ }
74
+
75
+ int narsil_split(const narsil_language *language, const uint16_t *units, uint32_t length, narsil_spans *parts) {
76
+ parts->length = 0;
77
+ size_t start = 0;
78
+ size_t index = 0;
79
+ while (index < length) {
80
+ size_t separator = index;
81
+ if (narsil_language_keeps(language, next_split_unit(language, units, length, &index))) { continue; }
82
+ int status = narsil_spans_push(parts, span_of(start, separator));
83
+ if (status != NARSIL_OK) { return status; }
84
+ for (;;) {
85
+ size_t before = index;
86
+ if (index >= length || narsil_language_keeps(language, next_split_unit(language, units, length, &index))) {
87
+ index = before;
88
+ break;
89
+ }
90
+ }
91
+ start = index;
92
+ }
93
+ return narsil_spans_push(parts, span_of(start, length));
94
+ }
95
+
96
+ static int is_mark(uint32_t code_point) {
97
+ if (code_point < LOWEST_MARK_CODE_POINT) { return 0; }
98
+ if (code_point >= HAN_UNIFIED_START && code_point <= HAN_UNIFIED_END) { return 0; }
99
+ if (code_point >= HIRAGANA_BLOCK_START && code_point <= KATAKANA_BLOCK_END) {
100
+ return code_point == COMBINING_VOICED_MARK || code_point == COMBINING_SEMI_VOICED_MARK;
101
+ }
102
+ if (code_point >= HANGUL_SYLLABLE_START && code_point <= HANGUL_SYLLABLE_END) { return 0; }
103
+ if (code_point >= HAN_EXTENSION_A_START && code_point <= HAN_EXTENSION_A_END) { return 0; }
104
+ return (narsil_unicode_properties(code_point) & NARSIL_UNICODE_MARK) != 0;
105
+ }
106
+
107
+ static uint32_t script_in_block(uint32_t code_point, uint32_t block_script) {
108
+ return narsil_unicode_script(code_point) == block_script ? block_script : NARSIL_UNICODE_SCRIPT_OTHER;
109
+ }
110
+
111
+ static uint32_t classify_southeast_asian(uint32_t code_point) {
112
+ if (code_point <= THAI_BLOCK_END) { return script_in_block(code_point, NARSIL_UNICODE_SCRIPT_THAI); }
113
+ if (code_point <= LAO_BLOCK_END) { return script_in_block(code_point, NARSIL_UNICODE_SCRIPT_LAO); }
114
+ if (code_point >= MYANMAR_BLOCK_START && code_point <= MYANMAR_BLOCK_END) {
115
+ return script_in_block(code_point, NARSIL_UNICODE_SCRIPT_MYANMAR);
116
+ }
117
+ if (code_point >= KHMER_BLOCK_START && code_point <= KHMER_BLOCK_END) {
118
+ return script_in_block(code_point, NARSIL_UNICODE_SCRIPT_KHMER);
119
+ }
120
+ return narsil_unicode_script(code_point);
121
+ }
122
+
123
+ static uint32_t prolonged_sound_kind(uint32_t current) {
124
+ return current == NARSIL_UNICODE_SCRIPT_HIRAGANA ? NARSIL_UNICODE_SCRIPT_HIRAGANA : NARSIL_UNICODE_SCRIPT_KATAKANA;
125
+ }
126
+
127
+ static uint32_t classify(uint32_t code_point) {
128
+ if (code_point < LOWEST_NGRAM_CODE_POINT) { return NARSIL_UNICODE_SCRIPT_OTHER; }
129
+ if (code_point < SOUTHEAST_ASIAN_BLOCKS_END) { return classify_southeast_asian(code_point); }
130
+ if (code_point >= HIRAGANA_BLOCK_START && code_point <= HIRAGANA_BLOCK_END) { return NARSIL_UNICODE_SCRIPT_HIRAGANA; }
131
+ if (code_point >= KATAKANA_BLOCK_START && code_point <= KATAKANA_BLOCK_END) { return NARSIL_UNICODE_SCRIPT_KATAKANA; }
132
+ if (code_point >= HAN_UNIFIED_START && code_point <= HAN_UNIFIED_END) { return NARSIL_UNICODE_SCRIPT_HAN; }
133
+ if (code_point >= HAN_EXTENSION_A_START && code_point <= HAN_EXTENSION_A_END) { return NARSIL_UNICODE_SCRIPT_HAN; }
134
+ if (code_point >= HANGUL_SYLLABLE_START && code_point <= HANGUL_SYLLABLE_END) { return NARSIL_UNICODE_SCRIPT_HANGUL; }
135
+ if (code_point >= HAN_COMPATIBILITY_START && code_point <= HAN_COMPATIBILITY_END) {
136
+ return NARSIL_UNICODE_SCRIPT_HAN;
137
+ }
138
+ if (code_point == IDEOGRAPHIC_ITERATION_MARK) { return NARSIL_UNICODE_SCRIPT_HAN; }
139
+ return narsil_unicode_script(code_point);
140
+ }
141
+
142
+ static int emit_run(narsil_span part, const narsil_code_points *offsets, uint32_t kind, uint32_t size,
143
+ narsil_spans *out) {
144
+ if (offsets->length < 2) { return NARSIL_OK; }
145
+ size_t count = offsets->length - 1;
146
+ const uint32_t *boundaries = offsets->values;
147
+ if (kind == NARSIL_UNICODE_SCRIPT_OTHER || count <= size) {
148
+ return narsil_spans_push(out, span_of((size_t)part.start + boundaries[0], (size_t)part.start + boundaries[count]));
149
+ }
150
+ for (size_t first = 0; first + size <= count; first++) {
151
+ int status = narsil_spans_push(
152
+ out, span_of((size_t)part.start + boundaries[first], (size_t)part.start + boundaries[first + size]));
153
+ if (status != NARSIL_OK) { return status; }
154
+ }
155
+ return NARSIL_OK;
156
+ }
157
+
158
+ int narsil_expand_ngrams(const uint16_t *units, narsil_span part, uint32_t size, narsil_spans *out,
159
+ narsil_code_points *offsets) {
160
+ const uint16_t *text = units + part.start;
161
+ size_t length = part.length;
162
+ offsets->length = 0;
163
+ if (length == 0) { return NARSIL_OK; }
164
+ uint32_t kind = NARSIL_UNICODE_SCRIPT_OTHER;
165
+ size_t index = 0;
166
+ int status = NARSIL_OK;
167
+ while (index < length && status == NARSIL_OK) {
168
+ size_t start = index;
169
+ uint32_t code_point = narsil_decode_next(text, length, &index);
170
+ if (offsets->length > 0 && is_mark(code_point)) { continue; }
171
+ uint32_t next = code_point == PROLONGED_SOUND_MARK ? prolonged_sound_kind(kind) : classify(code_point);
172
+ if (offsets->length > 0 && next != kind) {
173
+ status = narsil_code_points_push(offsets, (uint32_t)start);
174
+ if (status == NARSIL_OK) { status = emit_run(part, offsets, kind, size, out); }
175
+ offsets->length = 0;
176
+ }
177
+ kind = next;
178
+ if (status == NARSIL_OK) { status = narsil_code_points_push(offsets, (uint32_t)start); }
179
+ }
180
+ if (status == NARSIL_OK) { status = narsil_code_points_push(offsets, (uint32_t)length); }
181
+ if (status == NARSIL_OK) { status = emit_run(part, offsets, kind, size, out); }
182
+ return status;
183
+ }
@@ -0,0 +1,27 @@
1
+ #ifndef NARSIL_ANALYSIS_SPLIT_H
2
+ #define NARSIL_ANALYSIS_SPLIT_H
3
+
4
+ #include "languages.h"
5
+
6
+ #include <stddef.h>
7
+ #include <stdint.h>
8
+
9
+ typedef struct {
10
+ uint32_t start;
11
+ uint32_t length;
12
+ } narsil_span;
13
+
14
+ typedef struct {
15
+ narsil_span *spans;
16
+ size_t length;
17
+ size_t capacity;
18
+ } narsil_spans;
19
+
20
+ int narsil_spans_push(narsil_spans *spans, narsil_span span);
21
+ void narsil_spans_release(narsil_spans *spans);
22
+
23
+ int narsil_split(const narsil_language *language, const uint16_t *units, uint32_t length, narsil_spans *parts);
24
+ int narsil_expand_ngrams(const uint16_t *units, narsil_span part, uint32_t size, narsil_spans *out,
25
+ narsil_code_points *offsets);
26
+
27
+ #endif
@@ -0,0 +1,82 @@
1
+ #include "stop_words.h"
2
+
3
+ #include "../../include/narsil_core.h"
4
+ #include "text.h"
5
+
6
+ #include <stddef.h>
7
+ #include <stdint.h>
8
+ #include <stdlib.h>
9
+ #include <string.h>
10
+
11
+ #define FNV_OFFSET_BASIS 2166136261U
12
+ #define FNV_PRIME 16777619U
13
+ #define MIN_SLOTS 8U
14
+ #define MAX_STOP_WORDS (1U << 28)
15
+ #define EMPTY_SLOT 0U
16
+
17
+ static uint32_t hash_units(const uint16_t *units, size_t length) {
18
+ uint32_t hash = FNV_OFFSET_BASIS;
19
+ for (size_t i = 0; i < length; i++) {
20
+ hash ^= units[i];
21
+ hash *= FNV_PRIME;
22
+ }
23
+ return hash;
24
+ }
25
+
26
+ static uint32_t word_length(const narsil_stop_words *set, uint32_t word) {
27
+ return set->offsets[word + 1] - set->offsets[word];
28
+ }
29
+
30
+ static int slot_holds(const narsil_stop_words *set, uint32_t slot, const uint16_t *units, size_t length) {
31
+ uint32_t word = set->slots[slot] - 1;
32
+ return narsil_units_equal(set->units + set->offsets[word], word_length(set, word), units, length);
33
+ }
34
+
35
+ void narsil_stop_words_release(narsil_stop_words *set) {
36
+ free(set->units);
37
+ free(set->offsets);
38
+ free(set->slots);
39
+ memset(set, 0, sizeof(*set));
40
+ }
41
+
42
+ int narsil_stop_words_build(narsil_stop_words *set, const uint16_t *units, const uint32_t *offsets, uint32_t count) {
43
+ memset(set, 0, sizeof(*set));
44
+ if (count > MAX_STOP_WORDS) { return NARSIL_INVALID_ARGUMENT; }
45
+ for (uint32_t word = 0; word < count; word++) {
46
+ if (offsets[word + 1] < offsets[word]) { return NARSIL_INVALID_ARGUMENT; }
47
+ }
48
+ size_t total = offsets[count];
49
+ uint32_t slots = MIN_SLOTS;
50
+ while (slots < count * 2U) { slots *= 2U; }
51
+ set->units = malloc((total == 0 ? 1 : total) * sizeof(uint16_t));
52
+ set->offsets = malloc(((size_t)count + 1) * sizeof(uint32_t));
53
+ set->slots = calloc(slots, sizeof(uint32_t));
54
+ if (set->units == NULL || set->offsets == NULL || set->slots == NULL) {
55
+ narsil_stop_words_release(set);
56
+ return NARSIL_OUT_OF_MEMORY;
57
+ }
58
+ if (total > 0) { memcpy(set->units, units, total * sizeof(uint16_t)); }
59
+ memcpy(set->offsets, offsets, ((size_t)count + 1) * sizeof(uint32_t));
60
+ set->count = count;
61
+ set->slot_mask = slots - 1U;
62
+ for (uint32_t word = 0; word < count; word++) {
63
+ const uint16_t *word_units = set->units + offsets[word];
64
+ uint32_t length = word_length(set, word);
65
+ uint32_t slot = hash_units(word_units, length) & set->slot_mask;
66
+ while (set->slots[slot] != EMPTY_SLOT && !slot_holds(set, slot, word_units, length)) {
67
+ slot = (slot + 1U) & set->slot_mask;
68
+ }
69
+ set->slots[slot] = word + 1U;
70
+ }
71
+ return NARSIL_OK;
72
+ }
73
+
74
+ int narsil_stop_words_contains(const narsil_stop_words *set, const uint16_t *units, size_t length) {
75
+ if (set->slots == NULL) { return 0; }
76
+ uint32_t slot = hash_units(units, length) & set->slot_mask;
77
+ while (set->slots[slot] != EMPTY_SLOT) {
78
+ if (slot_holds(set, slot, units, length)) { return 1; }
79
+ slot = (slot + 1U) & set->slot_mask;
80
+ }
81
+ return 0;
82
+ }
@@ -0,0 +1,19 @@
1
+ #ifndef NARSIL_ANALYSIS_STOP_WORDS_H
2
+ #define NARSIL_ANALYSIS_STOP_WORDS_H
3
+
4
+ #include <stddef.h>
5
+ #include <stdint.h>
6
+
7
+ typedef struct {
8
+ uint16_t *units;
9
+ uint32_t *offsets;
10
+ uint32_t count;
11
+ uint32_t *slots;
12
+ uint32_t slot_mask;
13
+ } narsil_stop_words;
14
+
15
+ int narsil_stop_words_build(narsil_stop_words *set, const uint16_t *units, const uint32_t *offsets, uint32_t count);
16
+ int narsil_stop_words_contains(const narsil_stop_words *set, const uint16_t *units, size_t length);
17
+ void narsil_stop_words_release(narsil_stop_words *set);
18
+
19
+ #endif
@@ -0,0 +1,88 @@
1
+ #include "term_cache.h"
2
+
3
+ #include <stddef.h>
4
+ #include <stdint.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+
8
+ #define TERM_CACHE_SLOTS 16384U
9
+ #define TERM_CACHE_WAYS 8U
10
+ #define TERM_CACHE_SETS (TERM_CACHE_SLOTS / TERM_CACHE_WAYS)
11
+ #define TERM_CACHE_SET_MASK (TERM_CACHE_SETS - 1U)
12
+ #define TERM_FNV_OFFSET_BASIS 2166136261U
13
+ #define TERM_FNV_PRIME 16777619U
14
+ #define TERM_TAG_LANGUAGE_SHIFT 8U
15
+ #define TERM_TAG_EMPTY 0U
16
+
17
+ static uint32_t tag_of(const narsil_term_key *key) {
18
+ return ((key->language_index + 1U) << TERM_TAG_LANGUAGE_SHIFT) | key->flags;
19
+ }
20
+
21
+ static int holds(const narsil_term_slot *slot, uint32_t tag, const narsil_term_key *key) {
22
+ return slot->tag == tag && slot->key_length == key->length &&
23
+ memcmp(slot->key, key->units, key->length * sizeof *key->units) == 0;
24
+ }
25
+
26
+ static int prepared(narsil_term_cache *cache) {
27
+ if (cache->slots != NULL) { return 1; }
28
+ if (cache->unavailable) { return 0; }
29
+ cache->slots = calloc(TERM_CACHE_SLOTS, sizeof *cache->slots);
30
+ cache->next_victim = calloc(TERM_CACHE_SETS, sizeof *cache->next_victim);
31
+ if (cache->slots == NULL || cache->next_victim == NULL) {
32
+ free(cache->slots);
33
+ free(cache->next_victim);
34
+ cache->slots = NULL;
35
+ cache->next_victim = NULL;
36
+ cache->unavailable = 1;
37
+ return 0;
38
+ }
39
+ return 1;
40
+ }
41
+
42
+ narsil_term_slot *narsil_term_cache_find(narsil_term_cache *cache, const narsil_term_key *key,
43
+ narsil_term_slot **victim) {
44
+ *victim = NULL;
45
+ if (key->length == 0 || key->length > NARSIL_TERM_CACHE_UNITS || !prepared(cache)) { return NULL; }
46
+ uint32_t tag = tag_of(key);
47
+ uint32_t hash = (TERM_FNV_OFFSET_BASIS ^ tag) * TERM_FNV_PRIME;
48
+ for (size_t unit = 0; unit < key->length; unit++) {
49
+ hash ^= key->units[unit];
50
+ hash *= TERM_FNV_PRIME;
51
+ }
52
+ uint32_t set = hash & TERM_CACHE_SET_MASK;
53
+ narsil_term_slot *ways = &cache->slots[(size_t)set * TERM_CACHE_WAYS];
54
+ narsil_term_slot *empty = NULL;
55
+ for (uint32_t way = 0; way < TERM_CACHE_WAYS; way++) {
56
+ if (holds(&ways[way], tag, key)) { return &ways[way]; }
57
+ if (empty == NULL && ways[way].tag == TERM_TAG_EMPTY) { empty = &ways[way]; }
58
+ }
59
+ if (empty == NULL) {
60
+ uint8_t *next = &cache->next_victim[set];
61
+ empty = &ways[*next];
62
+ *next = (uint8_t)((*next + 1U) % TERM_CACHE_WAYS);
63
+ }
64
+ *victim = empty;
65
+ return NULL;
66
+ }
67
+
68
+ int narsil_term_cache_store(narsil_term_slot *slot, const narsil_term_key *key, const uint16_t *value, size_t length) {
69
+ if (length == 0 || length > NARSIL_TERM_CACHE_UNITS) { return 0; }
70
+ slot->tag = tag_of(key);
71
+ slot->key_length = (uint16_t)key->length;
72
+ memcpy(slot->key, key->units, key->length * sizeof *key->units);
73
+ slot->value_length = (uint16_t)length;
74
+ memcpy(slot->value, value, length * sizeof *value);
75
+ return 1;
76
+ }
77
+
78
+ uint32_t narsil_term_cache_index(const narsil_term_cache *cache, const narsil_term_slot *slot) {
79
+ return (uint32_t)(slot - cache->slots);
80
+ }
81
+
82
+ void narsil_term_cache_release(narsil_term_cache *cache) {
83
+ free(cache->slots);
84
+ free(cache->next_victim);
85
+ cache->slots = NULL;
86
+ cache->next_victim = NULL;
87
+ cache->unavailable = 0;
88
+ }