diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-04-02 22:54:23 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-04-02 22:54:23 +0200 |
| commit | a93e4fd376d990ead254657228e75715b74ca0ac (patch) | |
| tree | 0b5a12034639058875befb5f2146c67c9fd95173 /libbb | |
| parent | 8b0f459af7aa108089d0f87b0be81ccadb8638cb (diff) | |
| download | busybox-w32-a93e4fd376d990ead254657228e75715b74ca0ac.tar.gz busybox-w32-a93e4fd376d990ead254657228e75715b74ca0ac.tar.bz2 busybox-w32-a93e4fd376d990ead254657228e75715b74ca0ac.zip | |
find_applet_by_name: add an example of faster linear search code
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
| -rw-r--r-- | libbb/appletlib.c | 80 |
1 files changed, 77 insertions, 3 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index aeaf238f1..18583f91a 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
| @@ -141,10 +141,28 @@ void FAST_FUNC bb_show_usage(void) | |||
| 141 | 141 | ||
| 142 | int FAST_FUNC find_applet_by_name(const char *name) | 142 | int FAST_FUNC find_applet_by_name(const char *name) |
| 143 | { | 143 | { |
| 144 | unsigned i, max; | 144 | unsigned i, j, max; |
| 145 | int j; | ||
| 146 | const char *p; | 145 | const char *p; |
| 147 | 146 | ||
| 147 | /* The commented-out word-at-a-time code is ~40% faster, but +160 bytes. | ||
| 148 | * "Faster" here saves ~0.5 microsecond of real time - not worth it. | ||
| 149 | */ | ||
| 150 | #if 0 /*BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN*/ | ||
| 151 | uint32_t n32; | ||
| 152 | |||
| 153 | /* Handle all names < 2 chars long early */ | ||
| 154 | if (name[0] == '\0') | ||
| 155 | return -1; /* "" is not a valid applet name */ | ||
| 156 | if (name[1] == '\0') { | ||
| 157 | if (!ENABLE_TEST) | ||
| 158 | return -1; /* 1-char name is not valid */ | ||
| 159 | if (name[0] != ']') | ||
| 160 | return -1; /* 1-char name which isn't "[" is not valid */ | ||
| 161 | /* applet "[" is always applet #0: */ | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | #endif | ||
| 165 | |||
| 148 | p = applet_names; | 166 | p = applet_names; |
| 149 | i = 0; | 167 | i = 0; |
| 150 | #if KNOWN_APPNAME_OFFSETS <= 0 | 168 | #if KNOWN_APPNAME_OFFSETS <= 0 |
| @@ -166,7 +184,62 @@ int FAST_FUNC find_applet_by_name(const char *name) | |||
| 166 | //bb_error_msg("name:'%s' starting from:'%s' i:%u max:%u", name, p, i, max); | 184 | //bb_error_msg("name:'%s' starting from:'%s' i:%u max:%u", name, p, i, max); |
| 167 | #endif | 185 | #endif |
| 168 | 186 | ||
| 169 | /* Open-coding without strcmp/strlen calls for speed */ | 187 | /* Open-coded linear seatch without strcmp/strlen calls for speed */ |
| 188 | |||
| 189 | #if 0 /*BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN*/ | ||
| 190 | /* skip "[\0" name, it's surely not it */ | ||
| 191 | if (ENABLE_TEST && LONE_CHAR(p, '[')) | ||
| 192 | i++, p += 2; | ||
| 193 | /* All remaining applet names in p[] are at least 2 chars long */ | ||
| 194 | /* name[] is also at least 2 chars long */ | ||
| 195 | |||
| 196 | n32 = (name[0] << 0) | (name[1] << 8) | (name[2] << 16); | ||
| 197 | while (i < max) { | ||
| 198 | uint32_t p32; | ||
| 199 | char ch; | ||
| 200 | |||
| 201 | /* Quickly check match of the first 3 bytes */ | ||
| 202 | move_from_unaligned32(p32, p); | ||
| 203 | p += 3; | ||
| 204 | if ((p32 & 0x00ffffff) != n32) { | ||
| 205 | /* Most likely case: 3 first bytes do not match */ | ||
| 206 | i++; | ||
| 207 | if ((p32 & 0x00ff0000) == '\0') | ||
| 208 | continue; // p[2] was NUL | ||
| 209 | p++; | ||
| 210 | if ((p32 & 0xff000000) == '\0') | ||
| 211 | continue; // p[3] was NUL | ||
| 212 | /* p[0..3] aren't matching and none is NUL, check the rest */ | ||
| 213 | while (*p++ != '\0') | ||
| 214 | continue; | ||
| 215 | continue; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* Unlikely branch: first 3 bytes ([0..2]) match */ | ||
| 219 | if ((p32 & 0x00ff0000) == '\0') { | ||
| 220 | /* name is 2-byte long, it is full match */ | ||
| 221 | //bb_error_msg("found:'%s' i:%u", name, i); | ||
| 222 | return i; | ||
| 223 | } | ||
| 224 | /* Check remaining bytes [3..NUL] */ | ||
| 225 | ch = (p32 >> 24); | ||
| 226 | j = 3; | ||
| 227 | while (ch == name[j]) { | ||
| 228 | if (ch == '\0') { | ||
| 229 | //bb_error_msg("found:'%s' i:%u", name, i); | ||
| 230 | return i; | ||
| 231 | } | ||
| 232 | ch = *++p; | ||
| 233 | j++; | ||
| 234 | } | ||
| 235 | /* Not a match. Skip it, including NUL */ | ||
| 236 | while (ch != '\0') | ||
| 237 | ch = *++p; | ||
| 238 | p++; | ||
| 239 | i++; | ||
| 240 | } | ||
| 241 | return -1; | ||
| 242 | #else | ||
| 170 | while (i < max) { | 243 | while (i < max) { |
| 171 | char ch; | 244 | char ch; |
| 172 | j = 0; | 245 | j = 0; |
| @@ -189,6 +262,7 @@ int FAST_FUNC find_applet_by_name(const char *name) | |||
| 189 | i++; | 262 | i++; |
| 190 | } | 263 | } |
| 191 | return -1; | 264 | return -1; |
| 265 | #endif | ||
| 192 | } | 266 | } |
| 193 | 267 | ||
| 194 | 268 | ||
