fis-gtm/sr_port/do_patsplit.c

363 lines
12 KiB
C

/****************************************************************
* *
* Copyright 2001, 2009 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include "patcode.h"
#include "copy.h"
#include "min_max.h"
#include "gtm_string.h"
#ifdef UNICODE_SUPPORTED
#include "gtm_utf8.h"
#endif
GBLREF boolean_t gtm_utf8_mode;
/* This routine tries to split the pattern-string P into substrings LFR where F is a fixed length pattern-atom of P
* and L and R are the pattern substrings in P on the left and right side of F.
* For pattern-strings that have more than one fixed-length pattern-atom, the one closest to the median is selected.
* Once F is determined, do_patfixed() is invoked to determine all possible matches of F with the input string.
* do_patsplit() has additional optimizations to try match the fixed length pattern in a restricted subset of the
* input string taking into account the min and max of the left and the right pattern.
* For each such match, an attempt is made to match L and R with the left and right side of the input string.
* This is done using do_patfixed() or do_pattern() appropriately.
* If any such attempt succeeds, we return TRUE.
* If no attempt succeeds, we return FALSE.
* If the pattern-string P doesn't contain any fixed-length pattern-atom, we return DO_PATSPLIT_FAIL
*/
int do_patsplit(mval *str, mval *pat)
{
int4 count, total_min, total_max;
int4 min[MAX_PATTERN_ATOMS], max[MAX_PATTERN_ATOMS], size[MAX_PATTERN_ATOMS];
int4 bytelen, charlen, charstoskip, fixedcharlen, leftcharlen, rightcharlen, deltalen, numchars;
int4 strbytelen, strcharlen;
int4 alt_rep_min, alt_rep_max;
int4 alt;
uint4 tempuint;
uint4 code, flags;
uint4 *patptr, *patptr_start, *patptr_end, *fixed_patptr, *right_patptr, *tmp_patptr;
ptstr left_ptstr, right_ptstr, fixed_ptstr;
mval left_pat, right_pat, fixed_pat, left_str, right_str, fixed_str;
int4 index, fixed_index; /* index of our current fixed-length pattern-atom */
boolean_t right; /* 0 indicates we are processing left side, 1 indicates right side */
boolean_t fixed[2]; /* fixed[0] is for the left, fixed[1] is for the right */
int4 tot_min[2], tot_max[2], cnt[2]; /* index 0 is for left, index 1 is for right */
int4 offset;
unsigned char *strptr, *strtop, *rightptr, *rightnext, *fixedptr, *fixednext, *maxfixedptr;
boolean_t match; /* match status of input pattern with input string */
gtm_uint64_t bound;
MV_FORCE_STR(str);
patptr = (uint4 *)pat->str.addr;
DEBUG_ONLY(
GET_ULONG(tempuint, patptr);
assert(!tempuint);
)
patptr++;
patptr_start = patptr + 1;
GET_ULONG(tempuint, patptr);
patptr += tempuint;
patptr_end = patptr;
GET_LONG(count, patptr);
patptr++;
GET_LONG(total_min, patptr);
patptr++;
GET_LONG(total_max, patptr);
patptr++;
UNICODE_ONLY(
if (gtm_utf8_mode)
{
MV_FORCE_LEN(str); /* to set str.char_len if not already done */
assert(str->str.char_len >= total_min && str->str.char_len <= total_max);
}
)
assert(count <= MAX_PATTERN_ATOMS);
memcpy(&min[0], patptr, SIZEOF(*patptr) * count);
patptr += count;
memcpy(&max[0], patptr, SIZEOF(*patptr) * count);
patptr += count;
memcpy(&size[0], patptr, SIZEOF(*patptr) * count);
patptr = patptr_start;
right = FALSE; /* start with left side */
fixed[right] = TRUE;
tot_min[right] = tot_max[right] = 0;
fixed_patptr = right_patptr = NULL;
fixed_index = -1;
for (index = 0; index < count; index++)
{
GET_ULONG(code, patptr);
tmp_patptr = patptr;
patptr++;
if (code & PATM_ALT)
{ /* skip to the next pattern-atom */
GET_LONG(alt_rep_min, patptr);
patptr++;
GET_LONG(alt_rep_max, patptr);
patptr++;
GET_LONG(alt, patptr);
patptr++;
while(alt)
{
patptr += alt;
GET_LONG(alt, patptr);
patptr++;
}
fixed[right] = FALSE;
/* patptr now points to the next patcode after the alternation */
} else if (code == PATM_DFA)
{ /* Discrete Finite Automaton pat atom */
assert(min[index] != max[index]); /* DFA should never be fixed length */
GET_LONG(bytelen, patptr);
patptr++;
patptr += bytelen;
fixed[right] = FALSE;
} else
{
if (code & PATM_STRLIT)
{ /* STRLIT pat atom */
assert(3 == PAT_STRLIT_PADDING);
GET_LONG(bytelen, patptr);
patptr++;
GET_LONG(charlen, patptr);
patptr++;
GET_ULONG(flags, patptr);
patptr++;
patptr += DIVIDE_ROUND_UP(bytelen, SIZEOF(*patptr));
}
if ((min[index] == max[index]) && (bound = (gtm_uint64_t)min[index] * size[index]))
{ /* fixed_length */
if (ABS(index - (count / 2)) < ABS(fixed_index - (count / 2)))
{ /* non-zero fixed length pattern with a fixed_index closer to the median of the array */
if (right)
{ /* update left's tot_min and tot_max to reflect the new fixed_index */
tot_min[0] += tot_min[right] +
BOUND_MULTIPLY(min[fixed_index], size[fixed_index], bound);
if (tot_min[0] > PAT_MAX_REPEAT)
tot_min[0] = PAT_MAX_REPEAT;
tot_max[0] += tot_max[right] +
BOUND_MULTIPLY(max[fixed_index], size[fixed_index], bound);
if (tot_max[0] > PAT_MAX_REPEAT)
tot_max[0] = PAT_MAX_REPEAT;
fixed[0] &= fixed[right];
}
fixed_index = index;
right = TRUE;
fixed[right] = TRUE;
tot_min[right] = tot_max[right] = 0;
fixed_patptr = tmp_patptr;
right_patptr = patptr;
continue;
}
} else
fixed[right] = FALSE;
}
tot_min[right] += BOUND_MULTIPLY(min[index], size[index], bound);
if (tot_min[right] > PAT_MAX_REPEAT)
tot_min[right] = PAT_MAX_REPEAT;
tot_max[right] += BOUND_MULTIPLY(max[index], size[index], bound);
if (tot_max[right] > PAT_MAX_REPEAT)
tot_max[right] = PAT_MAX_REPEAT;
}
assert(index == count);
if (-1 == fixed_index)
return DO_PATSPLIT_FAIL;
assert(fixed_index < count);
assert((total_min == (tot_min[0] + tot_min[1] + BOUND_MULTIPLY(min[fixed_index], size[fixed_index], bound))) ||
(PAT_MAX_REPEAT == total_min));
assert((total_max == (tot_max[0] + tot_max[1] + BOUND_MULTIPLY(max[fixed_index], size[fixed_index], bound))) ||
(PAT_MAX_REPEAT == total_max));
cnt[0] = fixed_index;
if (cnt[0])
{ /* left section has at least one pattern atom. create its compilation string */
patptr = left_ptstr.buff;
*patptr++ = fixed[0];
*patptr++ = (uint4)(fixed_patptr - patptr_start + 1);
memcpy(patptr, patptr_start, (char *)fixed_patptr - (char *)patptr_start);
patptr += fixed_patptr - patptr_start;
*patptr++ = cnt[0];
*patptr++ = tot_min[0];
*patptr++ = tot_max[0];
for (index = 0; index < cnt[0]; index++)
*patptr++ = min[index];
if (!fixed[0])
{
for (index = 0; index < cnt[0]; index++)
*patptr++ = max[index];
}
for (index = 0; index < cnt[0]; index++)
*patptr++ = size[index];
left_pat.mvtype = MV_STR;
left_pat.str.len = INTCAST((char *)patptr - (char *)&left_ptstr.buff[0]);
left_pat.str.addr = (char *)&left_ptstr.buff[0];
}
/* create fixed length pattern atom's compilation string */
patptr = fixed_ptstr.buff;
*patptr++ = TRUE; /* fixed length pattern */
*patptr++ = (uint4)(right_patptr - fixed_patptr + 1);
memcpy(patptr, fixed_patptr, (char *)right_patptr - (char *)fixed_patptr);
patptr += right_patptr - fixed_patptr;
*patptr++ = 1; /* count */
fixedcharlen = min[fixed_index] * size[fixed_index]; /* tot_min and tot_max */
*patptr++ = fixedcharlen;
*patptr++ = fixedcharlen;
*patptr++ = min[fixed_index]; /* min[0] */
*patptr++ = size[fixed_index]; /* size[0] */
fixed_pat.mvtype = MV_STR;
fixed_pat.str.len = INTCAST((char *)patptr - (char *)&fixed_ptstr.buff[0]);
fixed_pat.str.addr = (char *)&fixed_ptstr.buff[0];
cnt[1] = count - fixed_index - 1;
if (cnt[1])
{ /* right section has at least one pattern atom. create its compilation string */
patptr = right_ptstr.buff;
*patptr++ = fixed[1];
*patptr++ = (uint4)(patptr_end - right_patptr + 1);
memcpy(patptr, right_patptr, (char *)patptr_end - (char *)right_patptr);
patptr += patptr_end - right_patptr;
*patptr++ = cnt[1];
*patptr++ = tot_min[1];
*patptr++ = tot_max[1];
for (index = fixed_index + 1; index < count; index++)
*patptr++ = min[index];
if (!fixed[1])
{
for (index = fixed_index + 1; index < count; index++)
*patptr++ = max[index];
}
for (index = fixed_index + 1; index < count; index++)
*patptr++ = size[index];
right_pat.mvtype = MV_STR;
right_pat.str.len = INTCAST((char *)patptr - (char *)&right_ptstr.buff[0]);
right_pat.str.addr = (char *)&right_ptstr.buff[0];
}
strbytelen = str->str.len;
strptr = (unsigned char *)str->str.addr;
strtop = strptr + strbytelen;
if (!gtm_utf8_mode)
strcharlen = str->str.len;
UNICODE_ONLY(
else
strcharlen = str->str.char_len;
)
/* Determine "maxfixedptr" */
if (strcharlen > (tot_min[1] + tot_max[0] + fixedcharlen))
charstoskip = tot_max[0];
else
charstoskip = strcharlen - tot_min[1] - fixedcharlen;
if (!gtm_utf8_mode)
strptr += charstoskip;
UNICODE_ONLY(
else
{
for ( ; 0 < charstoskip; charstoskip--)
{
assert(strptr < strtop); /* below macro relies on this */
strptr = UTF8_MBNEXT(strptr, strtop);
}
}
)
maxfixedptr = strptr;
/* Determine "fixedptr" */
strptr = (unsigned char *)str->str.addr;
if (strcharlen > (tot_min[0] + tot_max[1] + fixedcharlen))
charstoskip = strcharlen - tot_max[1] - fixedcharlen;
else
charstoskip = tot_min[0];
leftcharlen = charstoskip;
if (!gtm_utf8_mode)
strptr += charstoskip;
UNICODE_ONLY(
else
{
for ( ; 0 < charstoskip; charstoskip--)
{
assert(strptr < strtop); /* below macro relies on this */
strptr = UTF8_MBNEXT(strptr, strtop);
}
}
)
fixedptr = strptr;
/* Set "left_str" */
left_str.mvtype = MV_STR;
left_str.str.addr = str->str.addr;
/* Set "right_str" */
right_str.mvtype = MV_STR;
/* Set "fixed_str" */
fixed_str.mvtype = MV_STR;
if (!gtm_utf8_mode)
{
fixed_str.str.len = fixedcharlen;
rightptr = fixedptr + fixedcharlen;
}
UNICODE_ONLY(
else
{
left_str.mvtype |= MV_UTF_LEN; /* avoid recomputing "char_len" in do_patfixed below */
right_str.mvtype |= MV_UTF_LEN; /* avoid recomputing "char_len" in do_patfixed below */
fixed_str.mvtype |= MV_UTF_LEN; /* avoid recomputing "char_len" in do_patfixed below */
fixed_str.str.char_len = fixedcharlen;
/* skip fixedcharlen characters */
assert(fixedptr == strptr);
for (numchars = 0; numchars < fixedcharlen; numchars++)
{
assert(strptr < strtop);
strptr = UTF8_MBNEXT(strptr, strtop);
}
rightptr = strptr;
}
)
deltalen = 0;
/* Try to match the fixed pattern string and for each match, try matching the left and right input strings */
for (match = FALSE; !match && (fixedptr <= maxfixedptr); fixedptr = fixednext, rightptr = rightnext, leftcharlen++)
{
fixed_str.str.addr = (char *)fixedptr;
fixed_str.str.len = INTCAST(rightptr - fixedptr);
if (!gtm_utf8_mode)
{
fixednext = fixedptr + 1;
rightnext = rightptr + 1;
}
UNICODE_ONLY(
else
{
assert(fixedptr < strtop);
fixednext = UTF8_MBNEXT(fixedptr, strtop);
assert((rightptr < strtop) || (fixedptr == maxfixedptr) && (fixednext > maxfixedptr));
if (rightptr < strtop)
rightnext = UTF8_MBNEXT(rightptr, strtop);
}
)
if (!do_patfixed(&fixed_str, &fixed_pat))
continue;
assert(cnt[0] || cnt[1]); /* fixed_pat takes only one pattern atom and non-zero rest are in cnt[0] and cnt[1] */
if (cnt[0])
{
left_str.str.len = INTCAST(fixedptr - (unsigned char *)left_str.str.addr);
UNICODE_ONLY(left_str.str.char_len = leftcharlen;)
match = fixed[0] ? do_patfixed(&left_str, &left_pat) : do_pattern(&left_str, &left_pat);
if (!match)
continue;
}
if (cnt[1])
{
right_str.str.addr = (char *)rightptr;
UNICODE_ONLY(right_str.str.char_len = strcharlen - leftcharlen - fixedcharlen;)
right_str.str.len = INTCAST(strtop - rightptr);
match = (fixed[1] ? do_patfixed(&right_str, &right_pat) : do_pattern(&right_str, &right_pat));
}
}
return match;
}