find_applet_by_name: add an example of faster linear search code
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		| @@ -141,10 +141,28 @@ void FAST_FUNC bb_show_usage(void) | ||||
|  | ||||
| int FAST_FUNC find_applet_by_name(const char *name) | ||||
| { | ||||
| 	unsigned i, max; | ||||
| 	int j; | ||||
| 	unsigned i, j, max; | ||||
| 	const char *p; | ||||
|  | ||||
| /* The commented-out word-at-a-time code is ~40% faster, but +160 bytes. | ||||
|  * "Faster" here saves ~0.5 microsecond of real time - not worth it. | ||||
|  */ | ||||
| #if 0 /*BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN*/ | ||||
| 	uint32_t n32; | ||||
|  | ||||
| 	/* Handle all names < 2 chars long early */ | ||||
| 	if (name[0] == '\0') | ||||
| 		return -1; /* "" is not a valid applet name */ | ||||
| 	if (name[1] == '\0') { | ||||
| 		if (!ENABLE_TEST) | ||||
| 			return -1; /* 1-char name is not valid */ | ||||
| 		if (name[0] != ']') | ||||
| 			return -1; /* 1-char name which isn't "[" is not valid */ | ||||
| 		/* applet "[" is always applet #0: */ | ||||
| 		return 0; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	p = applet_names; | ||||
| 	i = 0; | ||||
| #if KNOWN_APPNAME_OFFSETS <= 0 | ||||
| @@ -166,7 +184,62 @@ int FAST_FUNC find_applet_by_name(const char *name) | ||||
| 	//bb_error_msg("name:'%s' starting from:'%s' i:%u max:%u", name, p, i, max); | ||||
| #endif | ||||
|  | ||||
| 	/* Open-coding without strcmp/strlen calls for speed */ | ||||
| 	/* Open-coded linear seatch without strcmp/strlen calls for speed */ | ||||
|  | ||||
| #if 0 /*BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN*/ | ||||
| 	/* skip "[\0" name, it's surely not it */ | ||||
| 	if (ENABLE_TEST && LONE_CHAR(p, '[')) | ||||
| 		i++, p += 2; | ||||
| 	/* All remaining applet names in p[] are at least 2 chars long */ | ||||
| 	/* name[] is also at least 2 chars long */ | ||||
|  | ||||
| 	n32 = (name[0] << 0) | (name[1] << 8) | (name[2] << 16); | ||||
| 	while (i < max) { | ||||
| 		uint32_t p32; | ||||
| 		char ch; | ||||
|  | ||||
| 		/* Quickly check match of the first 3 bytes */ | ||||
| 		move_from_unaligned32(p32, p); | ||||
| 		p += 3; | ||||
| 		if ((p32 & 0x00ffffff) != n32) { | ||||
| 			/* Most likely case: 3 first bytes do not match */ | ||||
| 			i++; | ||||
| 			if ((p32 & 0x00ff0000) == '\0') | ||||
| 				continue; // p[2] was NUL | ||||
| 			p++; | ||||
| 			if ((p32 & 0xff000000) == '\0') | ||||
| 				continue; // p[3] was NUL | ||||
| 			/* p[0..3] aren't matching and none is NUL, check the rest */ | ||||
| 			while (*p++ != '\0') | ||||
| 				continue; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		/* Unlikely branch: first 3 bytes ([0..2]) match */ | ||||
| 		if ((p32 & 0x00ff0000) == '\0') { | ||||
| 			/* name is 2-byte long, it is full match */ | ||||
| 			//bb_error_msg("found:'%s' i:%u", name, i); | ||||
| 			return i; | ||||
| 		} | ||||
| 		/* Check remaining bytes [3..NUL] */ | ||||
| 		ch = (p32 >> 24); | ||||
| 		j = 3; | ||||
| 		while (ch == name[j]) { | ||||
| 			if (ch == '\0') { | ||||
| 				//bb_error_msg("found:'%s' i:%u", name, i); | ||||
| 				return i; | ||||
| 			} | ||||
| 			ch = *++p; | ||||
| 			j++; | ||||
| 		} | ||||
| 		/* Not a match. Skip it, including NUL */ | ||||
| 		while (ch != '\0') | ||||
| 			ch = *++p; | ||||
| 		p++; | ||||
| 		i++; | ||||
| 	} | ||||
| 	return -1; | ||||
| #else | ||||
| 	while (i < max) { | ||||
| 		char ch; | ||||
| 		j = 0; | ||||
| @@ -189,6 +262,7 @@ int FAST_FUNC find_applet_by_name(const char *name) | ||||
| 		i++; | ||||
| 	} | ||||
| 	return -1; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user