Skip to content

Commit

Permalink
Add branchless is_alnum borrowed from MSVC++'s std::regex' _Is_word; …
Browse files Browse the repository at this point in the history
…should be about 5x faster. (#823)

The _Is_word change resulted in the following results in microbenchmarks; the previous is_alnum looks like branching_ranges.

.\word_character_test.exe
08/01/18 16:33:03
Running .\word_character_test.exe
Run on (12 X 2904 MHz CPU s)
CPU Caches:
  L1 Data 32K (x6)
  L1 Instruction 32K (x6)
  L2 Unified 262K (x6)
  L3 Unified 12582K (x1)
--------------------------------------------------------
Benchmark                 Time           CPU Iterations
--------------------------------------------------------
strchr_search    19426572900 ns 19421875000 ns          1
branching_ranges 7582129000 ns 7578125000 ns          1
branching_search 6592977800 ns 6593750000 ns          1
table_index      1091321300 ns 1078125000 ns          1
  • Loading branch information
BillyONeal authored and ras0219-msft committed Aug 1, 2018
1 parent 35f721d commit c55ada9
Showing 1 changed file with 39 additions and 4 deletions.
43 changes: 39 additions & 4 deletions Release/include/cpprest/asyncrt_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <system_error>
#include <random>
#include <locale.h>
#include <limits.h>
#include "pplx/pplxtasks.h"
#include "cpprest/details/basic_types.h"

Expand Down Expand Up @@ -356,11 +357,45 @@ namespace details
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
/// taking global lock for performance reasons.
/// </summary>
inline bool __cdecl is_alnum(char ch)
inline bool __cdecl is_alnum(const unsigned char uch) noexcept
{ // test if uch is an alnum character
// special casing char to avoid branches
static constexpr bool is_alnum_table[UCHAR_MAX + 1] =
{
/* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */
/* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */
/* 4X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */
/* 5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
/* 6X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */
/* 7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
/* non-ASCII values initialized to 0 */
};
return (is_alnum_table[uch]);
}

/// <summary>
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
/// taking global lock for performance reasons.
/// </summary>
inline bool __cdecl is_alnum(const char ch) noexcept
{
return (is_alnum(static_cast<unsigned char>(ch)));
}

/// <summary>
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
/// taking global lock for performance reasons.
/// </summary>
template<class Elem>
inline bool __cdecl is_alnum(Elem ch) noexcept
{
return (ch >= '0' && ch <= '9')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= 'a' && ch <= 'z');
// assumes 'x' == L'x' for the ASCII range
typedef typename std::make_unsigned<Elem>::type UElem;
const auto uch = static_cast<UElem>(ch);
return (uch <= static_cast<UElem>('z') && is_alnum(static_cast<unsigned char>(uch)));
}

/// <summary>
Expand Down

0 comments on commit c55ada9

Please sign in to comment.