MCPcopy Create free account
hub / github.com/pydata/numexpr / two_way_long_needle

Function two_way_long_needle

numexpr3/string_functions.hpp:319–437  ·  view source on GitHub ↗

Return the first location of non-empty NEEDLE within HAYSTACK, or NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This method is optimized for LONG_NEEDLE_THRESHOLD <= NEEDLE_LEN. Performance is guaranteed to be linear, with an initialization cost of 3 * NEEDLE_LEN + (1 << CHAR_BIT) operations. If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at most

Source from the content-addressed store, hash-verified

317 HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and
318 sublinear performance is not possible. */
319static RETURN_TYPE
320two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
321 const unsigned char *needle, size_t needle_len)
322{
323 size_t i; /* Index into current byte of NEEDLE. */
324 size_t j; /* Index into current window of HAYSTACK. */
325 size_t period; /* The period of the right half of needle. */
326 size_t suffix; /* The index of the right half of needle. */
327 size_t shift_table[1U << CHAR_BIT]; /* See below. */
328
329 /* Factor the needle into two halves, such that the left half is
330 smaller than the global period, and the right half is
331 periodic (with a period as large as NEEDLE_LEN - suffix). */
332 suffix = critical_factorization (needle, needle_len, &period);
333
334 /* Populate shift_table. For each possible byte value c,
335 shift_table[c] is the distance from the last occurrence of c to
336 the end of NEEDLE, or NEEDLE_LEN if c is absent from the NEEDLE.
337 shift_table[NEEDLE[NEEDLE_LEN - 1]] contains the only 0. */
338 for (i = 0; i < 1U << CHAR_BIT; i++)
339 shift_table[i] = needle_len;
340 for (i = 0; i < needle_len; i++)
341 shift_table[CANON_ELEMENT (needle[i])] = needle_len - i - 1;
342
343 /* Perform the search. Each iteration compares the right half
344 first. */
345 if (CMP_FUNC (needle, needle + period, suffix) == 0)
346 {
347 /* Entire needle is periodic; a mismatch can only advance by the
348 period, so use memory to avoid rescanning known occurrences
349 of the period. */
350 size_t memory = 0;
351 size_t shift;
352 j = 0;
353 while (AVAILABLE (haystack, haystack_len, j, needle_len))
354 {
355 /* Check the last byte first; if it does not match, then
356 shift to the next possible match location. */
357 shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])];
358 if (0 < shift)
359 {
360 if (memory && shift < period)
361 {
362 /* Since needle is periodic, but the last period has
363 a byte out of place, there can be no match until
364 after the mismatch. */
365 shift = needle_len - period;
366 }
367 memory = 0;
368 j += shift;
369 continue;
370 }
371 /* Scan for matches in right half. The last byte has
372 already been matched, by virtue of the shift table. */
373 i = MAX (suffix, memory);
374 while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
375 == CANON_ELEMENT (haystack[i + j])))
376 ++i;

Callers 1

stringcontainsFunction · 0.85

Calls 1

critical_factorizationFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…