Skip to content

Commit

Permalink
* string/Makefile (distribute): Add str-two-way.h.
Browse files Browse the repository at this point in the history
2008-03-29  Eric Blake	<ebb9@byu.net>

	Rewrite string searches to O(n) rather than O(n^2).
	* string/str-two-way.h: New file.  For linear fixed-allocation
	string searching.
	* string/memmem.c: New implementation.
	* string/strstr.c: New implementation.
	* string/strcasestr.c: New implementation.

	* sysdeps/posix/getaddrinfo.c (getaddrinfo): Call _res_hconf_init
  • Loading branch information
Ulrich Drepper committed May 15, 2008
1 parent b194db7 commit 0caca71
Show file tree
Hide file tree
Showing 9 changed files with 623 additions and 238 deletions.
15 changes: 14 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
2008-05-14 Ulrich Drepper <drepper@redhat.com>

* string/Makefile (distribute): Add str-two-way.h.

2008-03-29 Eric Blake <ebb9@byu.net>

Rewrite string searches to O(n) rather than O(n^2).
* string/str-two-way.h: New file. For linear fixed-allocation
string searching.
* string/memmem.c: New implementation.
* string/strstr.c: New implementation.
* string/strcasestr.c: New implementation.

2008-04-11 Paolo Bonzini <bonzini@gnu.org>

* posix/regcomp.c (optimize_utf8): Add a note on why we test
Expand Down Expand Up @@ -47,7 +60,7 @@
(match_prefix): Don't treat IPv4 loopback address special when
converting to v4 mapped addressed.

* sysdeps/posix/getaddrinfo.c (getaddrinfo): Add _res_hconf_init
* sysdeps/posix/getaddrinfo.c (getaddrinfo): Call _res_hconf_init
if necessary.
* posix/tst-rfc3484.c: Add dummy definition of _res_hconf_init.
* posix/tst-rfc3484-2.c: Likewise.
Expand Down
7 changes: 7 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ Version 2.9

* getaddrinfo now handles DCCP and UDPlite.
Implemented by Ulrich Drepper.

* New fixed-size conversion macros: htobe16, htole16, be16toh, le16toh,
htobe32, htole32, be32toh, le32toh, htobe64, htole64, be64toh, le64toh.
Implemented by Ulrich Drepper.

* New implementation of memmem, strstr, and strcasestr which is O(n).
Implemented by Eric Blake.

Version 2.8

Expand Down
48 changes: 22 additions & 26 deletions posix/regcomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,9 @@ optimize_utf8 (re_dfa_t *dfa)
case BUF_LAST:
break;
default:
/* Word anchors etc. cannot be handled. */
/* Word anchors etc. cannot be handled. It's okay to test
opr.ctx_type since constraints (for all DFA nodes) are
created by ORing one or more opr.ctx_type values. */
return;
}
break;
Expand Down Expand Up @@ -1318,6 +1320,8 @@ calc_first (void *extra, bin_tree_t *node)
node->node_idx = re_dfa_add_node (dfa, node->token);
if (BE (node->node_idx == -1, 0))
return REG_ESPACE;
if (node->token.type == ANCHOR)
dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type;
}
return REG_NOERROR;
}
Expand Down Expand Up @@ -1446,22 +1450,17 @@ duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node,
destination. */
org_dest = dfa->edests[org_node].elems[0];
re_node_set_empty (dfa->edests + clone_node);
if (dfa->nodes[org_node].type == ANCHOR)
/* If the node is root_node itself, it means the epsilon clsoure
has a loop. Then tie it to the destination of the root_node. */
if (org_node == root_node && clone_node != org_node)
{
/* In case of the node has another constraint, append it. */
if (org_node == root_node && clone_node != org_node)
{
/* ...but if the node is root_node itself, it means the
epsilon closure have a loop, then tie it to the
destination of the root_node. */
ret = re_node_set_insert (dfa->edests + clone_node,
org_dest);
if (BE (ret < 0, 0))
return REG_ESPACE;
break;
}
constraint |= dfa->nodes[org_node].opr.ctx_type;
ret = re_node_set_insert (dfa->edests + clone_node, org_dest);
if (BE (ret < 0, 0))
return REG_ESPACE;
break;
}
/* In case of the node has another constraint, add it. */
constraint |= dfa->nodes[org_node].constraint;
clone_dest = duplicate_node (dfa, org_dest, constraint);
if (BE (clone_dest == -1, 0))
return REG_ESPACE;
Expand All @@ -1479,7 +1478,7 @@ duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node,
clone_dest = search_duplicated_node (dfa, org_dest, constraint);
if (clone_dest == -1)
{
/* There are no such a duplicated node, create a new one. */
/* There is no such duplicated node, create a new one. */
reg_errcode_t err;
clone_dest = duplicate_node (dfa, org_dest, constraint);
if (BE (clone_dest == -1, 0))
Expand All @@ -1494,7 +1493,7 @@ duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node,
}
else
{
/* There are a duplicated node which satisfy the constraint,
/* There is a duplicated node which satisfies the constraint,
use it to avoid infinite loop. */
ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
if (BE (ret < 0, 0))
Expand Down Expand Up @@ -1543,8 +1542,7 @@ duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint)
if (BE (dup_idx != -1, 1))
{
dfa->nodes[dup_idx].constraint = constraint;
if (dfa->nodes[org_idx].type == ANCHOR)
dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type;
dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint;
dfa->nodes[dup_idx].duplicated = 1;

/* Store the index of the original node. */
Expand Down Expand Up @@ -1624,7 +1622,6 @@ static reg_errcode_t
calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root)
{
reg_errcode_t err;
unsigned int constraint;
int i, incomplete;
re_node_set eclosure;
incomplete = 0;
Expand All @@ -1636,15 +1633,14 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root)
We reference this value to avoid infinite loop. */
dfa->eclosures[node].nelem = -1;

constraint = ((dfa->nodes[node].type == ANCHOR)
? dfa->nodes[node].opr.ctx_type : 0);
/* If the current node has constraints, duplicate all nodes.
Since they must inherit the constraints. */
if (constraint
/* If the current node has constraints, duplicate all nodes
since they must inherit the constraints. */
if (dfa->nodes[node].constraint
&& dfa->edests[node].nelem
&& !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
{
err = duplicate_node_closure (dfa, node, node, node, constraint);
err = duplicate_node_closure (dfa, node, node, node,
dfa->nodes[node].constraint);
if (BE (err != REG_NOERROR, 0))
return err;
}
Expand Down
6 changes: 1 addition & 5 deletions posix/regex_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1665,11 +1665,9 @@ create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,

for (i = 0 ; i < nodes->nelem ; i++)
{
unsigned int constraint = 0;
re_token_t *node = dfa->nodes + nodes->elems[i];
re_token_type_t type = node->type;
if (node->constraint)
constraint = node->constraint;
unsigned int constraint = node->constraint;

if (type == CHARACTER && !constraint)
continue;
Expand All @@ -1682,8 +1680,6 @@ create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
newstate->halt = 1;
else if (type == OP_BACK_REF)
newstate->has_backref = 1;
else if (type == ANCHOR)
constraint = node->opr.ctx_type;

if (constraint)
{
Expand Down
3 changes: 2 additions & 1 deletion string/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ tests := tester inl-tester noinl-tester testcopy test-ffs \
tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \
bug-strtok1 $(addprefix test-,$(strop-tests)) \
bug-envz1 tst-strxfrm2 tst-endian
distribute := memcopy.h pagecopy.h tst-svc.expect test-string.h
distribute := memcopy.h pagecopy.h tst-svc.expect test-string.h \
str-two-way.h


include ../Rules
Expand Down
58 changes: 39 additions & 19 deletions string/memmem.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 1991,92,93,94,96,97,98,2000,2004 Free Software Foundation, Inc.
/* Copyright (C) 1991,92,93,94,96,97,98,2000,2004,2008 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Expand All @@ -16,26 +16,36 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */

#include <stddef.h>
/* This particular implementation was written by Eric Blake, 2008. */

#ifndef _LIBC
# include <config.h>
#endif

/* Specification of memmem. */
#include <string.h>

#ifndef _LIBC
# define __builtin_expect(expr, val) (expr)
#endif

#define RETURN_TYPE void *
#define AVAILABLE(h, h_l, j, n_l) ((j) <= (h_l) - (n_l))
#include "str-two-way.h"

#undef memmem

/* Return the first occurrence of NEEDLE in HAYSTACK. */
/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK
if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in
HAYSTACK. */
void *
memmem (haystack, haystack_len, needle, needle_len)
const void *haystack;
size_t haystack_len;
const void *needle;
size_t needle_len;
memmem (const void *haystack_start, size_t haystack_len,
const void *needle_start, size_t needle_len)
{
const char *begin;
const char *const last_possible
= (const char *) haystack + haystack_len - needle_len;
/* Abstract memory is considered to be an array of 'unsigned char' values,
not an array of 'char' values. See ISO C 99 section 6.2.6.1. */
const unsigned char *haystack = (const unsigned char *) haystack_start;
const unsigned char *needle = (const unsigned char *) needle_start;

if (needle_len == 0)
/* The first occurrence of the empty string is deemed to occur at
Expand All @@ -47,12 +57,22 @@ memmem (haystack, haystack_len, needle, needle_len)
if (__builtin_expect (haystack_len < needle_len, 0))
return NULL;

for (begin = (const char *) haystack; begin <= last_possible; ++begin)
if (begin[0] == ((const char *) needle)[0] &&
!memcmp ((const void *) &begin[1],
(const void *) ((const char *) needle + 1),
needle_len - 1))
return (void *) begin;

return NULL;
/* Use optimizations in memchr when possible, to reduce the search
size of haystack using a linear algorithm with a smaller
coefficient. However, avoid memchr for long needles, since we
can often achieve sublinear performance. */
if (needle_len < LONG_NEEDLE_THRESHOLD)
{
haystack = memchr (haystack, *needle, haystack_len);
if (!haystack || __builtin_expect (needle_len == 1, 0))
return (void *) haystack;
haystack_len -= haystack - (const unsigned char *) haystack_start;
if (haystack_len < needle_len)
return NULL;
return two_way_short_needle (haystack, haystack_len, needle, needle_len);
}
else
return two_way_long_needle (haystack, haystack_len, needle, needle_len);
}

#undef LONG_NEEDLE_THRESHOLD
Loading

0 comments on commit 0caca71

Please sign in to comment.