Simplify the CEscape conversion array and make it endian neutral PiperOrigin-RevId: 952312050 Change-Id: Iea0f73e2ab71c86dab0d6f4be15f8f0693768883
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc index 1ed7c24..efe9041 100644 --- a/absl/strings/escaping.cc +++ b/absl/strings/escaping.cc
@@ -389,39 +389,35 @@ }; /* clang-format on */ -constexpr uint32_t MakeCEscapedLittleEndianUint32(size_t c) { - size_t char_len = kCEscapedLen[c]; - if (char_len == 1) { - return static_cast<uint32_t>(c); - } - if (char_len == 2) { - switch (c) { - case '\n': - return '\\' | (static_cast<uint32_t>('n') << 8); - case '\r': - return '\\' | (static_cast<uint32_t>('r') << 8); - case '\t': - return '\\' | (static_cast<uint32_t>('t') << 8); - case '\"': - return '\\' | (static_cast<uint32_t>('\"') << 8); - case '\'': - return '\\' | (static_cast<uint32_t>('\'') << 8); - case '\\': - return '\\' | (static_cast<uint32_t>('\\') << 8); +constexpr std::array<std::array<char, 4>, 256> kCEscapedSequence = []() { + std::array<std::array<char, 4>, 256> a{}; + for (size_t c = 0; c < 256; ++c) { + size_t char_len = kCEscapedLen[c]; + if (char_len == 1) { + a[c][0] = static_cast<char>(c); + } else if (char_len == 2) { + a[c][0] = '\\'; + // clang-format off + switch (c) { + case '\n': a[c][1] = 'n'; break; + case '\r': a[c][1] = 'r'; break; + case '\t': a[c][1] = 't'; break; + case '\"': a[c][1] = '\"'; break; + case '\'': a[c][1] = '\''; break; + case '\\': a[c][1] = '\\'; break; + } + // clang-format on + } else { + assert(char_len == 4); + // A backslash followed by the octal value of the byte. + a[c][0] = '\\'; + a[c][1] = static_cast<char>('0' + (c / 64)); + a[c][2] = static_cast<char>('0' + ((c % 64) / 8)); + a[c][3] = static_cast<char>('0' + (c % 8)); } } - return static_cast<uint32_t>('\\' | (('0' + (c / 64)) << 8) | - (('0' + ((c % 64) / 8)) << 16) | - (('0' + (c % 8)) << 24)); -} - -template <size_t... indexes> -inline constexpr std::array<uint32_t, sizeof...(indexes)> -MakeCEscapedLittleEndianUint32Array(std::index_sequence<indexes...>) { - return {MakeCEscapedLittleEndianUint32(indexes)...}; -} -constexpr std::array<uint32_t, 256> kCEscapedLittleEndianUint32Array = - MakeCEscapedLittleEndianUint32Array(std::make_index_sequence<256>()); + return a; +}(); // Calculates the length of the C-style escaped version of 'src'. // Assumes that non-printable characters are escaped using octal sequences, and @@ -456,8 +452,8 @@ return; } - // We keep 3 slop bytes so that we can call `little_endian::Store32` - // invariably regardless of the length of the escaped character. + // The small `memcpy` is faster when the size is a compile-time constant, so + // keep 3 slop bytes so that we can call memcpy with size=4. constexpr size_t kSlopBytes = 3; ABSL_INTERNAL_CHECK( escaped_len <= std::numeric_limits<size_t>::max() - kSlopBytes, @@ -467,10 +463,8 @@ *dest, append_buf_len, [src, escaped_len](char* append_ptr, size_t) { for (char c : src) { unsigned char uc = static_cast<unsigned char>(c); - size_t char_len = kCEscapedLen[uc]; - uint32_t little_endian_uint32 = kCEscapedLittleEndianUint32Array[uc]; - little_endian::Store32(append_ptr, little_endian_uint32); - append_ptr += char_len; + memcpy(append_ptr, kCEscapedSequence[uc].data(), 4); + append_ptr += kCEscapedLen[uc]; } return escaped_len; });