LCOV - code coverage report
Current view: top level - src/backend/snowball/libstemmer - utilities.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 59.7 % 300 179
Test Date: 2026-02-28 04:14:42 Functions: 54.8 % 31 17
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           19 : extern symbol * create_s(void) {
      21              :     symbol * p;
      22           19 :     void * mem = malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol));
      23           19 :     if (mem == NULL)
      24            0 :         SNOWBALL_RETURN_OR_THROW(NULL, std::bad_alloc());
      25           19 :     p = (symbol *) (HEAD + (char *) mem);
      26           19 :     CAPACITY(p) = CREATE_SIZE;
      27           19 :     SET_SIZE(p, 0);
      28           19 :     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        22173 : extern int skip_utf8(const symbol * p, int c, int limit, int n) {
      44              :     int b;
      45        22173 :     if (n < 0) return -1;
      46        47333 :     for (; n > 0; n--) {
      47        28807 :         if (c >= limit) return -1;
      48        25160 :         b = p[c++];
      49        25160 :         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        18526 :     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          140 : extern int skip_b_utf8(const symbol * p, int c, int limit, int n) {
      69              :     int b;
      70          140 :     if (n < 0) return -1;
      71          280 :     for (; n > 0; n--) {
      72          140 :         if (c <= limit) return -1;
      73          140 :         b = p[--c];
      74          140 :         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          140 :     return c;
      83              : }
      84              : 
      85              : /* Code for character groupings: utf8 cases */
      86              : 
      87        33676 : static int get_utf8(const symbol * p, int c, int l, int * slot) {
      88              :     int b0, b1, b2;
      89        33676 :     if (c >= l) return 0;
      90        28516 :     b0 = p[c++];
      91        28516 :     if (b0 < 0xC0 || c == l) {   /* 1100 0000 */
      92        28516 :         *slot = b0;
      93        28516 :         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         2124 : static int get_b_utf8(const symbol * p, int c, int lb, int * slot) {
     110              :     int a, b;
     111         2124 :     if (c <= lb) return 0;
     112         2067 :     b = p[--c];
     113         2067 :     if (b < 0x80 || c == lb) {   /* 1000 0000 */
     114         2067 :         *slot = b;
     115         2067 :         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        22120 : 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        22954 :         int w = get_utf8(z->p, z->c, z->l, & ch);
     137        35660 :         if (!w) return -1;
     138        19264 :         if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
     139        12706 :             return w;
     140         6558 :         z->c += w;
     141         6558 :     } while (repeat);
     142         5724 :     return 0;
     143              : }
     144              : 
     145          421 : 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          421 :         int w = get_b_utf8(z->p, z->c, z->lb, & ch);
     149          643 :         if (!w) return -1;
     150          421 :         if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
     151          222 :             return w;
     152          199 :         z->c -= w;
     153          199 :     } while (repeat);
     154          199 :     return 0;
     155              : }
     156              : 
     157         5634 : 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        10722 :         int w = get_utf8(z->p, z->c, z->l, & ch);
     161        14886 :         if (!w) return -1;
     162         9252 :         if (!(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0))
     163         4164 :             return w;
     164         5088 :         z->c += w;
     165         5088 :     } while (repeat);
     166            0 :     return 0;
     167              : }
     168              : 
     169         1255 : 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         1703 :         int w = get_b_utf8(z->p, z->c, z->lb, & ch);
     173         2288 :         if (!w) return -1;
     174         1646 :         if (!(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0))
     175          585 :             return w;
     176         1061 :         z->c -= w;
     177         1061 :     } while (repeat);
     178          613 :     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          131 : extern int eq_s_b(struct SN_env * z, int s_size, const symbol * s) {
     237          131 :     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         2511 : 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         2511 :     int i = 0;
     253         2511 :     int j = v_size;
     254              : 
     255         2511 :     int c = z->c; int l = z->l;
     256         2511 :     const symbol * q = z->p + c;
     257              : 
     258              :     const struct among * w;
     259              : 
     260         2511 :     int common_i = 0;
     261         2511 :     int common_j = 0;
     262              : 
     263         2511 :     int first_key_inspected = 0;
     264              : 
     265         7174 :     while (1) {
     266         9685 :         int k = i + ((j - i) >> 1);
     267         9685 :         int diff = 0;
     268         9685 :         int common = common_i < common_j ? common_i : common_j; /* smaller */
     269         9685 :         w = v + k;
     270              :         {
     271        11741 :             int i2; for (i2 = common; i2 < w->s_size; i2++) {
     272        11723 :                 if (c + common == l) { diff = -1; break; }
     273        11687 :                 diff = q[common] - w->s[i2];
     274        11687 :                 if (diff != 0) break;
     275         2056 :                 common++;
     276              :             }
     277              :         }
     278         9685 :         if (diff < 0) {
     279         4744 :             j = k;
     280         4744 :             common_j = common;
     281              :         } else {
     282         4941 :             i = k;
     283         4941 :             common_i = common;
     284              :         }
     285         9685 :         if (j - i <= 1) {
     286         2814 :             if (i > 0) break; /* v->s has been inspected */
     287          606 :             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          519 :             if (first_key_inspected) break;
     294          303 :             first_key_inspected = 1;
     295              :         }
     296              :     }
     297         2511 :     w = v + i;
     298              :     while (1) {
     299         2511 :         if (common_i >= w->s_size) {
     300           18 :             z->c = c + w->s_size;
     301           18 :             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         2493 :         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         5379 : 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         5379 :     int i = 0;
     319         5379 :     int j = v_size;
     320              : 
     321         5379 :     int c = z->c; int lb = z->lb;
     322         5379 :     const symbol * q = z->p + c - 1;
     323              : 
     324              :     const struct among * w;
     325              : 
     326         5379 :     int common_i = 0;
     327         5379 :     int common_j = 0;
     328              : 
     329         5379 :     int first_key_inspected = 0;
     330              : 
     331        14716 :     while (1) {
     332        20095 :         int k = i + ((j - i) >> 1);
     333        20095 :         int diff = 0;
     334        20095 :         int common = common_i < common_j ? common_i : common_j;
     335        20095 :         w = v + k;
     336              :         {
     337        31323 :             int i2; for (i2 = w->s_size - 1 - common; i2 >= 0; i2--) {
     338        30065 :                 if (c - common == lb) { diff = -1; break; }
     339        30047 :                 diff = q[- common] - w->s[i2];
     340        30047 :                 if (diff != 0) break;
     341        11228 :                 common++;
     342              :             }
     343              :         }
     344        20095 :         if (diff < 0) { j = k; common_j = common; }
     345        10647 :                  else { i = k; common_i = common; }
     346        20095 :         if (j - i <= 1) {
     347         6535 :             if (i > 0) break;
     348         2312 :             if (j == i) break;
     349         1865 :             if (first_key_inspected) break;
     350         1156 :             first_key_inspected = 1;
     351              :         }
     352              :     }
     353         5379 :     w = v + i;
     354              :     while (1) {
     355         7234 :         if (common_i >= w->s_size) {
     356         1776 :             z->c = c - w->s_size;
     357         1776 :             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         5458 :         if (!w->substring_i) return 0;
     365         1855 :         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           19 : static int increase_size(symbol ** p, int n) {
     374           19 :     int new_size = n + 20;
     375           19 :     void * mem = realloc((char *) *p - HEAD,
     376              :                          HEAD + (new_size + 1) * sizeof(symbol));
     377              :     symbol * q;
     378           19 :     if (mem == NULL) return -1;
     379           19 :     q = (symbol *) (HEAD + (char *)mem);
     380           19 :     CAPACITY(q) = new_size;
     381           19 :     *p = q;
     382           19 :     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         4156 : extern SNOWBALL_ERR replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s)
     390              : {
     391         4156 :     int adjustment = s_size - (c_ket - c_bra);
     392         4156 :     if (adjustment != 0) {
     393         1849 :         int len = SIZE(z->p);
     394         1849 :         if (adjustment + len > CAPACITY(z->p)) {
     395           19 :             SNOWBALL_PROPAGATE_ERR(increase_size(&z->p, adjustment + len));
     396              :         }
     397         1849 :         memmove(z->p + c_ket + adjustment,
     398         1849 :                 z->p + c_ket,
     399         1849 :                 (len - c_ket) * sizeof(symbol));
     400         1849 :         SET_SIZE(z->p, adjustment + len);
     401         1849 :         z->l += adjustment;
     402         1849 :         if (z->c >= c_ket)
     403           55 :             z->c += adjustment;
     404         1794 :         else if (z->c > c_bra)
     405            0 :             z->c = c_bra;
     406              :     }
     407         4156 :     if (s_size) memmove(z->p + c_bra, s, s_size * sizeof(symbol));
     408         4156 :     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         1354 : static SNOWBALL_ERR slice_check(struct SN_env * z) {
     415              : 
     416         1354 :     if (z->bra < 0 ||
     417         1354 :         z->bra > z->ket ||
     418         1354 :         z->ket > z->l ||
     419         1354 :         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         1354 :     SNOWBALL_RETURN_OK;
     428              : }
     429              : 
     430              : # define SLICE_CHECK(Z) SNOWBALL_PROPAGATE_ERR(slice_check(Z))
     431              : 
     432          755 : extern SNOWBALL_ERR slice_from_s(struct SN_env * z, int s_size, const symbol * s) {
     433          755 :     SLICE_CHECK(z);
     434          755 :     REPLACE_S(z, z->bra, z->ket, s_size, s);
     435          755 :     z->ket = z->bra + s_size;
     436          755 :     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          599 : extern SNOWBALL_ERR slice_del(struct SN_env * z) {
     444          599 :     SLICE_CHECK(z);
     445              :     {
     446          599 :         int slice_size = z->ket - z->bra;
     447          599 :         if (slice_size != 0) {
     448          599 :             int len = SIZE(z->p);
     449          599 :             memmove(z->p + z->bra,
     450          599 :                     z->p + z->ket,
     451          599 :                     (len - z->ket) * sizeof(symbol));
     452          599 :             SET_SIZE(z->p, len - slice_size);
     453          599 :             z->l -= slice_size;
     454          599 :             if (z->c >= z->ket)
     455            0 :                 z->c -= slice_size;
     456          599 :             else if (z->c > z->bra)
     457            0 :                 z->c = z->bra;
     458              :         }
     459              :     }
     460          599 :     z->ket = z->bra;
     461          599 :     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 2.0-1