LCOV - code coverage report
Current view: top level - src/backend/snowball/libstemmer - utilities.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 179 300 59.7 %
Date: 2026-02-02 14:17:46 Functions: 17 31 54.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "snowball_runtime.h"
       2             : 
       3             : #ifdef SNOWBALL_RUNTIME_THROW_EXCEPTIONS
       4             : # include <new>
       5             : # include <stdexcept>
       6             : # define SNOWBALL_RETURN_OK return
       7             : # define SNOWBALL_RETURN_OR_THROW(R, E) throw E
       8             : # define SNOWBALL_PROPAGATE_ERR(F) F
       9             : #else
      10             : # define SNOWBALL_RETURN_OK return 0
      11             : # define SNOWBALL_RETURN_OR_THROW(R, E) return R
      12             : # define SNOWBALL_PROPAGATE_ERR(F) do { \
      13             :         int snowball_err = F; \
      14             :         if (snowball_err < 0) return snowball_err; \
      15             :     } while (0)
      16             : #endif
      17             : 
      18             : #define CREATE_SIZE 1
      19             : 
      20          38 : extern symbol * create_s(void) {
      21             :     symbol * p;
      22          38 :     void * mem = malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol));
      23          38 :     if (mem == NULL)
      24           0 :         SNOWBALL_RETURN_OR_THROW(NULL, std::bad_alloc());
      25          38 :     p = (symbol *) (HEAD + (char *) mem);
      26          38 :     CAPACITY(p) = CREATE_SIZE;
      27          38 :     SET_SIZE(p, 0);
      28          38 :     return p;
      29             : }
      30             : 
      31           0 : extern void lose_s(symbol * p) {
      32           0 :     if (p == NULL) return;
      33           0 :     free((char *) p - HEAD);
      34             : }
      35             : 
      36             : /*
      37             :    new_p = skip_utf8(p, c, l, n); skips n characters forwards from p + c.
      38             :    new_p is the new position, or -1 on failure.
      39             : 
      40             :    -- used to implement hop and next in the utf8 case.
      41             : */
      42             : 
      43       44346 : extern int skip_utf8(const symbol * p, int c, int limit, int n) {
      44             :     int b;
      45       44346 :     if (n < 0) return -1;
      46       94666 :     for (; n > 0; n--) {
      47       57614 :         if (c >= limit) return -1;
      48       50320 :         b = p[c++];
      49       50320 :         if (b >= 0xC0) {   /* 1100 0000 */
      50           0 :             while (c < limit) {
      51           0 :                 b = p[c];
      52           0 :                 if (b >= 0xC0 || b < 0x80) break;
      53             :                 /* break unless b is 10------ */
      54           0 :                 c++;
      55             :             }
      56             :         }
      57             :     }
      58       37052 :     return c;
      59             : }
      60             : 
      61             : /*
      62             :    new_p = skip_b_utf8(p, c, lb, n); skips n characters backwards from p + c - 1
      63             :    new_p is the new position, or -1 on failure.
      64             : 
      65             :    -- used to implement hop and next in the utf8 case.
      66             : */
      67             : 
      68         280 : extern int skip_b_utf8(const symbol * p, int c, int limit, int n) {
      69             :     int b;
      70         280 :     if (n < 0) return -1;
      71         560 :     for (; n > 0; n--) {
      72         280 :         if (c <= limit) return -1;
      73         280 :         b = p[--c];
      74         280 :         if (b >= 0x80) {   /* 1000 0000 */
      75           0 :             while (c > limit) {
      76           0 :                 b = p[c];
      77           0 :                 if (b >= 0xC0) break; /* 1100 0000 */
      78           0 :                 c--;
      79             :             }
      80             :         }
      81             :     }
      82         280 :     return c;
      83             : }
      84             : 
      85             : /* Code for character groupings: utf8 cases */
      86             : 
      87       67352 : static int get_utf8(const symbol * p, int c, int l, int * slot) {
      88             :     int b0, b1, b2;
      89       67352 :     if (c >= l) return 0;
      90       57032 :     b0 = p[c++];
      91       57032 :     if (b0 < 0xC0 || c == l) {   /* 1100 0000 */
      92       57032 :         *slot = b0;
      93       57032 :         return 1;
      94             :     }
      95           0 :     b1 = p[c++] & 0x3F;
      96           0 :     if (b0 < 0xE0 || c == l) {   /* 1110 0000 */
      97           0 :         *slot = (b0 & 0x1F) << 6 | b1;
      98           0 :         return 2;
      99             :     }
     100           0 :     b2 = p[c++] & 0x3F;
     101           0 :     if (b0 < 0xF0 || c == l) {   /* 1111 0000 */
     102           0 :         *slot = (b0 & 0xF) << 12 | b1 << 6 | b2;
     103           0 :         return 3;
     104             :     }
     105           0 :     *slot = (b0 & 0x7) << 18 | b1 << 12 | b2 << 6 | (p[c] & 0x3F);
     106           0 :     return 4;
     107             : }
     108             : 
     109        4248 : static int get_b_utf8(const symbol * p, int c, int lb, int * slot) {
     110             :     int a, b;
     111        4248 :     if (c <= lb) return 0;
     112        4134 :     b = p[--c];
     113        4134 :     if (b < 0x80 || c == lb) {   /* 1000 0000 */
     114        4134 :         *slot = b;
     115        4134 :         return 1;
     116             :     }
     117           0 :     a = b & 0x3F;
     118           0 :     b = p[--c];
     119           0 :     if (b >= 0xC0 || c == lb) {   /* 1100 0000 */
     120           0 :         *slot = (b & 0x1F) << 6 | a;
     121           0 :         return 2;
     122             :     }
     123           0 :     a |= (b & 0x3F) << 6;
     124           0 :     b = p[--c];
     125           0 :     if (b >= 0xE0 || c == lb) {   /* 1110 0000 */
     126           0 :         *slot = (b & 0xF) << 12 | a;
     127           0 :         return 3;
     128             :     }
     129           0 :     *slot = (p[--c] & 0x7) << 18 | (b & 0x3F) << 12 | a;
     130           0 :     return 4;
     131             : }
     132             : 
     133       44240 : extern int in_grouping_U(struct SN_env * z, const unsigned char * s, int min, int max, int repeat) {
     134             :     do {
     135             :         int ch;
     136       45908 :         int w = get_utf8(z->p, z->c, z->l, & ch);
     137       71320 :         if (!w) return -1;
     138       38528 :         if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
     139       25412 :             return w;
     140       13116 :         z->c += w;
     141       13116 :     } while (repeat);
     142       11448 :     return 0;
     143             : }
     144             : 
     145         842 : extern int in_grouping_b_U(struct SN_env * z, const unsigned char * s, int min, int max, int repeat) {
     146             :     do {
     147             :         int ch;
     148         842 :         int w = get_b_utf8(z->p, z->c, z->lb, & ch);
     149        1286 :         if (!w) return -1;
     150         842 :         if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
     151         444 :             return w;
     152         398 :         z->c -= w;
     153         398 :     } while (repeat);
     154         398 :     return 0;
     155             : }
     156             : 
     157       11268 : extern int out_grouping_U(struct SN_env * z, const unsigned char * s, int min, int max, int repeat) {
     158             :     do {
     159             :         int ch;
     160       21444 :         int w = get_utf8(z->p, z->c, z->l, & ch);
     161       29772 :         if (!w) return -1;
     162       18504 :         if (!(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0))
     163        8328 :             return w;
     164       10176 :         z->c += w;
     165       10176 :     } while (repeat);
     166           0 :     return 0;
     167             : }
     168             : 
     169        2510 : extern int out_grouping_b_U(struct SN_env * z, const unsigned char * s, int min, int max, int repeat) {
     170             :     do {
     171             :         int ch;
     172        3406 :         int w = get_b_utf8(z->p, z->c, z->lb, & ch);
     173        4576 :         if (!w) return -1;
     174        3292 :         if (!(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0))
     175        1170 :             return w;
     176        2122 :         z->c -= w;
     177        2122 :     } while (repeat);
     178        1226 :     return 0;
     179             : }
     180             : 
     181             : /* Code for character groupings: non-utf8 cases */
     182             : 
     183           0 : extern int in_grouping(struct SN_env * z, const unsigned char * s, int min, int max, int repeat) {
     184             :     do {
     185             :         int ch;
     186           0 :         if (z->c >= z->l) return -1;
     187           0 :         ch = z->p[z->c];
     188           0 :         if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
     189           0 :             return 1;
     190           0 :         z->c++;
     191           0 :     } while (repeat);
     192           0 :     return 0;
     193             : }
     194             : 
     195           0 : extern int in_grouping_b(struct SN_env * z, const unsigned char * s, int min, int max, int repeat) {
     196             :     do {
     197             :         int ch;
     198           0 :         if (z->c <= z->lb) return -1;
     199           0 :         ch = z->p[z->c - 1];
     200           0 :         if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
     201           0 :             return 1;
     202           0 :         z->c--;
     203           0 :     } while (repeat);
     204           0 :     return 0;
     205             : }
     206             : 
     207           0 : extern int out_grouping(struct SN_env * z, const unsigned char * s, int min, int max, int repeat) {
     208             :     do {
     209             :         int ch;
     210           0 :         if (z->c >= z->l) return -1;
     211           0 :         ch = z->p[z->c];
     212           0 :         if (!(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0))
     213           0 :             return 1;
     214           0 :         z->c++;
     215           0 :     } while (repeat);
     216           0 :     return 0;
     217             : }
     218             : 
     219           0 : extern int out_grouping_b(struct SN_env * z, const unsigned char * s, int min, int max, int repeat) {
     220             :     do {
     221             :         int ch;
     222           0 :         if (z->c <= z->lb) return -1;
     223           0 :         ch = z->p[z->c - 1];
     224           0 :         if (!(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0))
     225           0 :             return 1;
     226           0 :         z->c--;
     227           0 :     } while (repeat);
     228           0 :     return 0;
     229             : }
     230             : 
     231           0 : extern int eq_s(struct SN_env * z, int s_size, const symbol * s) {
     232           0 :     if (z->l - z->c < s_size || memcmp(z->p + z->c, s, s_size * sizeof(symbol)) != 0) return 0;
     233           0 :     z->c += s_size; return 1;
     234             : }
     235             : 
     236         262 : extern int eq_s_b(struct SN_env * z, int s_size, const symbol * s) {
     237         262 :     if (z->c - z->lb < s_size || memcmp(z->p + z->c - s_size, s, s_size * sizeof(symbol)) != 0) return 0;
     238           0 :     z->c -= s_size; return 1;
     239             : }
     240             : 
     241           0 : extern int eq_v(struct SN_env * z, const symbol * p) {
     242           0 :     return eq_s(z, SIZE(p), p);
     243             : }
     244             : 
     245           0 : extern int eq_v_b(struct SN_env * z, const symbol * p) {
     246           0 :     return eq_s_b(z, SIZE(p), p);
     247             : }
     248             : 
     249        5022 : extern int find_among(struct SN_env * z, const struct among * v, int v_size,
     250             :                       int (*call_among_func)(struct SN_env*)) {
     251             : 
     252        5022 :     int i = 0;
     253        5022 :     int j = v_size;
     254             : 
     255        5022 :     int c = z->c; int l = z->l;
     256        5022 :     const symbol * q = z->p + c;
     257             : 
     258             :     const struct among * w;
     259             : 
     260        5022 :     int common_i = 0;
     261        5022 :     int common_j = 0;
     262             : 
     263        5022 :     int first_key_inspected = 0;
     264             : 
     265       14348 :     while (1) {
     266       19370 :         int k = i + ((j - i) >> 1);
     267       19370 :         int diff = 0;
     268       19370 :         int common = common_i < common_j ? common_i : common_j; /* smaller */
     269       19370 :         w = v + k;
     270             :         {
     271       23482 :             int i2; for (i2 = common; i2 < w->s_size; i2++) {
     272       23446 :                 if (c + common == l) { diff = -1; break; }
     273       23374 :                 diff = q[common] - w->s[i2];
     274       23374 :                 if (diff != 0) break;
     275        4112 :                 common++;
     276             :             }
     277             :         }
     278       19370 :         if (diff < 0) {
     279        9488 :             j = k;
     280        9488 :             common_j = common;
     281             :         } else {
     282        9882 :             i = k;
     283        9882 :             common_i = common;
     284             :         }
     285       19370 :         if (j - i <= 1) {
     286        5628 :             if (i > 0) break; /* v->s has been inspected */
     287        1212 :             if (j == i) break; /* only one item in v */
     288             : 
     289             :             /* - but now we need to go round once more to get
     290             :                v->s inspected. This looks messy, but is actually
     291             :                the optimal approach.  */
     292             : 
     293        1038 :             if (first_key_inspected) break;
     294         606 :             first_key_inspected = 1;
     295             :         }
     296             :     }
     297        5022 :     w = v + i;
     298             :     while (1) {
     299        5022 :         if (common_i >= w->s_size) {
     300          36 :             z->c = c + w->s_size;
     301          36 :             if (!w->function) return w->result;
     302           0 :             z->af = w->function;
     303           0 :             if (call_among_func(z)) {
     304           0 :                 z->c = c + w->s_size;
     305           0 :                 return w->result;
     306             :             }
     307             :         }
     308        4986 :         if (!w->substring_i) return 0;
     309           0 :         w += w->substring_i;
     310             :     }
     311             : }
     312             : 
     313             : /* find_among_b is for backwards processing. Same comments apply */
     314             : 
     315       10758 : extern int find_among_b(struct SN_env * z, const struct among * v, int v_size,
     316             :                         int (*call_among_func)(struct SN_env*)) {
     317             : 
     318       10758 :     int i = 0;
     319       10758 :     int j = v_size;
     320             : 
     321       10758 :     int c = z->c; int lb = z->lb;
     322       10758 :     const symbol * q = z->p + c - 1;
     323             : 
     324             :     const struct among * w;
     325             : 
     326       10758 :     int common_i = 0;
     327       10758 :     int common_j = 0;
     328             : 
     329       10758 :     int first_key_inspected = 0;
     330             : 
     331       29432 :     while (1) {
     332       40190 :         int k = i + ((j - i) >> 1);
     333       40190 :         int diff = 0;
     334       40190 :         int common = common_i < common_j ? common_i : common_j;
     335       40190 :         w = v + k;
     336             :         {
     337       62646 :             int i2; for (i2 = w->s_size - 1 - common; i2 >= 0; i2--) {
     338       60130 :                 if (c - common == lb) { diff = -1; break; }
     339       60094 :                 diff = q[- common] - w->s[i2];
     340       60094 :                 if (diff != 0) break;
     341       22456 :                 common++;
     342             :             }
     343             :         }
     344       40190 :         if (diff < 0) { j = k; common_j = common; }
     345       21294 :                  else { i = k; common_i = common; }
     346       40190 :         if (j - i <= 1) {
     347       13070 :             if (i > 0) break;
     348        4624 :             if (j == i) break;
     349        3730 :             if (first_key_inspected) break;
     350        2312 :             first_key_inspected = 1;
     351             :         }
     352             :     }
     353       10758 :     w = v + i;
     354             :     while (1) {
     355       14468 :         if (common_i >= w->s_size) {
     356        3552 :             z->c = c - w->s_size;
     357        3552 :             if (!w->function) return w->result;
     358           0 :             z->af = w->function;
     359           0 :             if (call_among_func(z)) {
     360           0 :                 z->c = c - w->s_size;
     361           0 :                 return w->result;
     362             :             }
     363             :         }
     364       10916 :         if (!w->substring_i) return 0;
     365        3710 :         w += w->substring_i;
     366             :     }
     367             : }
     368             : 
     369             : 
     370             : /* Increase the size of the buffer pointed to by p to at least n symbols.
     371             :  * On success, returns 0.  If insufficient memory, returns -1.
     372             :  */
     373          38 : static int increase_size(symbol ** p, int n) {
     374          38 :     int new_size = n + 20;
     375          38 :     void * mem = realloc((char *) *p - HEAD,
     376             :                          HEAD + (new_size + 1) * sizeof(symbol));
     377             :     symbol * q;
     378          38 :     if (mem == NULL) return -1;
     379          38 :     q = (symbol *) (HEAD + (char *)mem);
     380          38 :     CAPACITY(q) = new_size;
     381          38 :     *p = q;
     382          38 :     return 0;
     383             : }
     384             : 
     385             : /* to replace symbols between c_bra and c_ket in z->p by the
     386             :    s_size symbols at s.
     387             :    Returns 0 on success, -1 on error.
     388             : */
     389        8312 : extern SNOWBALL_ERR replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s)
     390             : {
     391        8312 :     int adjustment = s_size - (c_ket - c_bra);
     392        8312 :     if (adjustment != 0) {
     393        3698 :         int len = SIZE(z->p);
     394        3698 :         if (adjustment + len > CAPACITY(z->p)) {
     395          38 :             SNOWBALL_PROPAGATE_ERR(increase_size(&z->p, adjustment + len));
     396             :         }
     397        3698 :         memmove(z->p + c_ket + adjustment,
     398        3698 :                 z->p + c_ket,
     399        3698 :                 (len - c_ket) * sizeof(symbol));
     400        3698 :         SET_SIZE(z->p, adjustment + len);
     401        3698 :         z->l += adjustment;
     402        3698 :         if (z->c >= c_ket)
     403         110 :             z->c += adjustment;
     404        3588 :         else if (z->c > c_bra)
     405           0 :             z->c = c_bra;
     406             :     }
     407        8312 :     if (s_size) memmove(z->p + c_bra, s, s_size * sizeof(symbol));
     408        8312 :     SNOWBALL_RETURN_OK;
     409             : }
     410             : 
     411             : # define REPLACE_S(Z, B, K, SIZE, S) \
     412             :     SNOWBALL_PROPAGATE_ERR(replace_s(Z, B, K, SIZE, S))
     413             : 
     414        2708 : static SNOWBALL_ERR slice_check(struct SN_env * z) {
     415             : 
     416        2708 :     if (z->bra < 0 ||
     417        2708 :         z->bra > z->ket ||
     418        2708 :         z->ket > z->l ||
     419        2708 :         z->l > SIZE(z->p)) /* this line could be removed */
     420             :     {
     421             : #if 0
     422             :         fprintf(stderr, "faulty slice operation:\n");
     423             :         debug(z, -1, 0);
     424             : #endif
     425           0 :         SNOWBALL_RETURN_OR_THROW(-1, std::logic_error("Snowball slice invalid"));
     426             :     }
     427        2708 :     SNOWBALL_RETURN_OK;
     428             : }
     429             : 
     430             : # define SLICE_CHECK(Z) SNOWBALL_PROPAGATE_ERR(slice_check(Z))
     431             : 
     432        1510 : extern SNOWBALL_ERR slice_from_s(struct SN_env * z, int s_size, const symbol * s) {
     433        1510 :     SLICE_CHECK(z);
     434        1510 :     REPLACE_S(z, z->bra, z->ket, s_size, s);
     435        1510 :     z->ket = z->bra + s_size;
     436        1510 :     SNOWBALL_RETURN_OK;
     437             : }
     438             : 
     439           0 : extern SNOWBALL_ERR slice_from_v(struct SN_env * z, const symbol * p) {
     440           0 :     return slice_from_s(z, SIZE(p), p);
     441             : }
     442             : 
     443        1198 : extern SNOWBALL_ERR slice_del(struct SN_env * z) {
     444        1198 :     SLICE_CHECK(z);
     445             :     {
     446        1198 :         int slice_size = z->ket - z->bra;
     447        1198 :         if (slice_size != 0) {
     448        1198 :             int len = SIZE(z->p);
     449        1198 :             memmove(z->p + z->bra,
     450        1198 :                     z->p + z->ket,
     451        1198 :                     (len - z->ket) * sizeof(symbol));
     452        1198 :             SET_SIZE(z->p, len - slice_size);
     453        1198 :             z->l -= slice_size;
     454        1198 :             if (z->c >= z->ket)
     455           0 :                 z->c -= slice_size;
     456        1198 :             else if (z->c > z->bra)
     457           0 :                 z->c = z->bra;
     458             :         }
     459             :     }
     460        1198 :     z->ket = z->bra;
     461        1198 :     SNOWBALL_RETURN_OK;
     462             : }
     463             : 
     464           0 : extern SNOWBALL_ERR insert_s(struct SN_env * z, int bra, int ket, int s_size, const symbol * s) {
     465           0 :     REPLACE_S(z, bra, ket, s_size, s);
     466           0 :     if (bra <= z->ket) {
     467           0 :         int adjustment = s_size - (ket - bra);
     468           0 :         z->ket += adjustment;
     469           0 :         if (bra <= z->bra) z->bra += adjustment;
     470             :     }
     471           0 :     SNOWBALL_RETURN_OK;
     472             : }
     473             : 
     474           0 : extern SNOWBALL_ERR insert_v(struct SN_env * z, int bra, int ket, const symbol * p) {
     475           0 :     return insert_s(z, bra, ket, SIZE(p), p);
     476             : }
     477             : 
     478           0 : extern SNOWBALL_ERR slice_to(struct SN_env * z, symbol ** p) {
     479           0 :     SLICE_CHECK(z);
     480             :     {
     481           0 :         int len = z->ket - z->bra;
     482           0 :         if (CAPACITY(*p) < len) {
     483           0 :             SNOWBALL_PROPAGATE_ERR(increase_size(p, len));
     484             :         }
     485           0 :         memmove(*p, z->p + z->bra, len * sizeof(symbol));
     486           0 :         SET_SIZE(*p, len);
     487             :     }
     488           0 :     SNOWBALL_RETURN_OK;
     489             : }
     490             : 
     491           0 : extern SNOWBALL_ERR assign_to(struct SN_env * z, symbol ** p) {
     492           0 :     int len = z->l;
     493           0 :     if (CAPACITY(*p) < len) {
     494           0 :         SNOWBALL_PROPAGATE_ERR(increase_size(p, len));
     495             :     }
     496           0 :     memmove(*p, z->p, len * sizeof(symbol));
     497           0 :     SET_SIZE(*p, len);
     498           0 :     SNOWBALL_RETURN_OK;
     499             : }
     500             : 
     501           0 : extern int len_utf8(const symbol * p) {
     502           0 :     int size = SIZE(p);
     503           0 :     int len = 0;
     504           0 :     while (size--) {
     505           0 :         symbol b = *p++;
     506           0 :         if (b >= 0xC0 || b < 0x80) ++len;
     507             :     }
     508           0 :     return len;
     509             : }

Generated by: LCOV version 1.16