diff options
author | anastasy888 <anastasy888@yandex-team.ru> | 2022-02-10 16:45:54 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:54 +0300 |
commit | 49f765d71da452ea93138a25559dfa68dd76c7f3 (patch) | |
tree | 1016041feb637349e401dcc0fa85217dd2c2c639 /contrib/restricted/abseil-cpp-tstring/y_absl/strings | |
parent | 7353a3fdea9c67c256980c00a2b3b67f09b23a27 (diff) | |
download | ydb-49f765d71da452ea93138a25559dfa68dd76c7f3.tar.gz |
Restoring authorship annotation for <anastasy888@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/abseil-cpp-tstring/y_absl/strings')
58 files changed, 12831 insertions, 12831 deletions
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ascii.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ascii.cc index 959d6c27ff..3643767807 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ascii.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ascii.cc @@ -1,200 +1,200 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/ascii.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace ascii_internal { - -// # Table generated by this Python code (bit 0x02 is currently unused): -// TODO(mbar) Move Python code for generation of table to BUILD and link here. - -// NOTE: The kAsciiPropertyBits table used within this code was generated by -// Python code of the following form. (Bit 0x02 is currently unused and -// available.) -// -// def Hex2(n): -// return '0x' + hex(n/16)[2:] + hex(n%16)[2:] -// def IsPunct(ch): -// return (ord(ch) >= 32 and ord(ch) < 127 and -// not ch.isspace() and not ch.isalnum()) -// def IsBlank(ch): -// return ch in ' \t' -// def IsCntrl(ch): -// return ord(ch) < 32 or ord(ch) == 127 -// def IsXDigit(ch): -// return ch.isdigit() or ch.lower() in 'abcdef' -// for i in range(128): -// ch = chr(i) -// mask = ((ch.isalpha() and 0x01 or 0) | -// (ch.isalnum() and 0x04 or 0) | -// (ch.isspace() and 0x08 or 0) | -// (IsPunct(ch) and 0x10 or 0) | -// (IsBlank(ch) and 0x20 or 0) | -// (IsCntrl(ch) and 0x40 or 0) | -// (IsXDigit(ch) and 0x80 or 0)) -// print Hex2(mask) + ',', -// if i % 16 == 7: -// print ' //', Hex2(i & 0x78) -// elif i % 16 == 15: -// print - -// clang-format off -// Array of bitfields holding character information. Each bit value corresponds -// to a particular character feature. For readability, and because the value -// of these bits is tightly coupled to this implementation, the individual bits -// are not named. Note that bitfields for all characters above ASCII 127 are -// zero-initialized. +namespace ascii_internal { + +// # Table generated by this Python code (bit 0x02 is currently unused): +// TODO(mbar) Move Python code for generation of table to BUILD and link here. + +// NOTE: The kAsciiPropertyBits table used within this code was generated by +// Python code of the following form. (Bit 0x02 is currently unused and +// available.) +// +// def Hex2(n): +// return '0x' + hex(n/16)[2:] + hex(n%16)[2:] +// def IsPunct(ch): +// return (ord(ch) >= 32 and ord(ch) < 127 and +// not ch.isspace() and not ch.isalnum()) +// def IsBlank(ch): +// return ch in ' \t' +// def IsCntrl(ch): +// return ord(ch) < 32 or ord(ch) == 127 +// def IsXDigit(ch): +// return ch.isdigit() or ch.lower() in 'abcdef' +// for i in range(128): +// ch = chr(i) +// mask = ((ch.isalpha() and 0x01 or 0) | +// (ch.isalnum() and 0x04 or 0) | +// (ch.isspace() and 0x08 or 0) | +// (IsPunct(ch) and 0x10 or 0) | +// (IsBlank(ch) and 0x20 or 0) | +// (IsCntrl(ch) and 0x40 or 0) | +// (IsXDigit(ch) and 0x80 or 0)) +// print Hex2(mask) + ',', +// if i % 16 == 7: +// print ' //', Hex2(i & 0x78) +// elif i % 16 == 15: +// print + +// clang-format off +// Array of bitfields holding character information. Each bit value corresponds +// to a particular character feature. For readability, and because the value +// of these bits is tightly coupled to this implementation, the individual bits +// are not named. Note that bitfields for all characters above ASCII 127 are +// zero-initialized. ABSL_DLL const unsigned char kPropertyBits[256] = { - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00 - 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10 - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20 - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, // 0x30 - 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40 - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50 - 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60 - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70 - 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40, -}; - -// Array of characters for the ascii_tolower() function. For values 'A' -// through 'Z', return the lower-case character; otherwise, return the -// identity of the passed character. + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00 + 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10 + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20 + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, // 0x30 + 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40 + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50 + 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60 + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70 + 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40, +}; + +// Array of characters for the ascii_tolower() function. For values 'A' +// through 'Z', return the lower-case character; otherwise, return the +// identity of the passed character. ABSL_DLL const char kToLower[256] = { - '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', - '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', - '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', - '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', - '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', - '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f', - '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', - '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', - '\x40', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', - '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', - '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', - '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', - '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f', - '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', - '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', - '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', - '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', - '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', - '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf', - '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7', - '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf', - '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', - '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', - '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', - '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', - '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', - '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', - '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', - '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', -}; - -// Array of characters for the ascii_toupper() function. For values 'a' -// through 'z', return the upper-case character; otherwise, return the -// identity of the passed character. + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', + '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', + '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', + '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f', + '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', + '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', + '\x40', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', + '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', + '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', + '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', + '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f', + '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', + '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', + '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', + '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', + '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', + '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf', + '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7', + '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf', + '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', + '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', + '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', + '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', + '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', + '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', + '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', + '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', +}; + +// Array of characters for the ascii_toupper() function. For values 'a' +// through 'z', return the upper-case character; otherwise, return the +// identity of the passed character. ABSL_DLL const char kToUpper[256] = { - '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', - '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', - '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', - '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', - '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', - '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f', - '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', - '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', - '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', - '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', - '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', - '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', - '\x60', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f', - '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', - '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', - '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', - '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', - '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', - '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf', - '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7', - '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf', - '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', - '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', - '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', - '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', - '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', - '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', - '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', - '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', -}; -// clang-format on - -} // namespace ascii_internal - + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', + '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', + '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', + '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f', + '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', + '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', + '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', + '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', + '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', + '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', + '\x60', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f', + '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', + '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', + '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', + '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', + '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', + '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf', + '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7', + '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf', + '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', + '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', + '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', + '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', + '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', + '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', + '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', + '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', +}; +// clang-format on + +} // namespace ascii_internal + void AsciiStrToLower(TString* s) { - for (auto& ch : *s) { + for (auto& ch : *s) { ch = y_absl::ascii_tolower(ch); - } -} - + } +} + void AsciiStrToUpper(TString* s) { - for (auto& ch : *s) { + for (auto& ch : *s) { ch = y_absl::ascii_toupper(ch); - } -} - + } +} + void RemoveExtraAsciiWhitespace(TString* str) { - auto stripped = StripAsciiWhitespace(*str); - - if (stripped.empty()) { - str->clear(); - return; - } - - auto input_it = stripped.begin(); - auto input_end = stripped.end(); - auto output_it = &(*str)[0]; - bool is_ws = false; - - for (; input_it < input_end; ++input_it) { - if (is_ws) { - // Consecutive whitespace? Keep only the last. + auto stripped = StripAsciiWhitespace(*str); + + if (stripped.empty()) { + str->clear(); + return; + } + + auto input_it = stripped.begin(); + auto input_end = stripped.end(); + auto output_it = &(*str)[0]; + bool is_ws = false; + + for (; input_it < input_end; ++input_it) { + if (is_ws) { + // Consecutive whitespace? Keep only the last. is_ws = y_absl::ascii_isspace(*input_it); - if (is_ws) --output_it; - } else { + if (is_ws) --output_it; + } else { is_ws = y_absl::ascii_isspace(*input_it); - } - - *output_it = *input_it; - ++output_it; - } - - str->erase(output_it - &(*str)[0]); -} - + } + + *output_it = *input_it; + ++output_it; + } + + str->erase(output_it - &(*str)[0]); +} + ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ascii.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ascii.h index bc04710d8c..3e78be8443 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ascii.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ascii.h @@ -1,242 +1,242 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: ascii.h -// ----------------------------------------------------------------------------- -// -// This package contains functions operating on characters and strings -// restricted to standard ASCII. These include character classification -// functions analogous to those found in the ANSI C Standard Library <ctype.h> -// header file. -// -// C++ implementations provide <ctype.h> functionality based on their -// C environment locale. In general, reliance on such a locale is not ideal, as -// the locale standard is problematic (and may not return invariant information -// for the same character set, for example). These `ascii_*()` functions are -// hard-wired for standard ASCII, much faster, and guaranteed to behave -// consistently. They will never be overloaded, nor will their function -// signature change. -// -// `ascii_isalnum()`, `ascii_isalpha()`, `ascii_isascii()`, `ascii_isblank()`, -// `ascii_iscntrl()`, `ascii_isdigit()`, `ascii_isgraph()`, `ascii_islower()`, -// `ascii_isprint()`, `ascii_ispunct()`, `ascii_isspace()`, `ascii_isupper()`, -// `ascii_isxdigit()` -// Analogous to the <ctype.h> functions with similar names, these -// functions take an unsigned char and return a bool, based on whether the -// character matches the condition specified. -// -// If the input character has a numerical value greater than 127, these -// functions return `false`. -// -// `ascii_tolower()`, `ascii_toupper()` -// Analogous to the <ctype.h> functions with similar names, these functions -// take an unsigned char and return a char. -// -// If the input character is not an ASCII {lower,upper}-case letter (including -// numerical values greater than 127) then the functions return the same value -// as the input character. - -#ifndef ABSL_STRINGS_ASCII_H_ -#define ABSL_STRINGS_ASCII_H_ - -#include <algorithm> +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: ascii.h +// ----------------------------------------------------------------------------- +// +// This package contains functions operating on characters and strings +// restricted to standard ASCII. These include character classification +// functions analogous to those found in the ANSI C Standard Library <ctype.h> +// header file. +// +// C++ implementations provide <ctype.h> functionality based on their +// C environment locale. In general, reliance on such a locale is not ideal, as +// the locale standard is problematic (and may not return invariant information +// for the same character set, for example). These `ascii_*()` functions are +// hard-wired for standard ASCII, much faster, and guaranteed to behave +// consistently. They will never be overloaded, nor will their function +// signature change. +// +// `ascii_isalnum()`, `ascii_isalpha()`, `ascii_isascii()`, `ascii_isblank()`, +// `ascii_iscntrl()`, `ascii_isdigit()`, `ascii_isgraph()`, `ascii_islower()`, +// `ascii_isprint()`, `ascii_ispunct()`, `ascii_isspace()`, `ascii_isupper()`, +// `ascii_isxdigit()` +// Analogous to the <ctype.h> functions with similar names, these +// functions take an unsigned char and return a bool, based on whether the +// character matches the condition specified. +// +// If the input character has a numerical value greater than 127, these +// functions return `false`. +// +// `ascii_tolower()`, `ascii_toupper()` +// Analogous to the <ctype.h> functions with similar names, these functions +// take an unsigned char and return a char. +// +// If the input character is not an ASCII {lower,upper}-case letter (including +// numerical values greater than 127) then the functions return the same value +// as the input character. + +#ifndef ABSL_STRINGS_ASCII_H_ +#define ABSL_STRINGS_ASCII_H_ + +#include <algorithm> #include <util/generic/string.h> - + #include "y_absl/base/attributes.h" #include "y_absl/base/config.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace ascii_internal { - -// Declaration for an array of bitfields holding character information. +namespace ascii_internal { + +// Declaration for an array of bitfields holding character information. ABSL_DLL extern const unsigned char kPropertyBits[256]; - -// Declaration for the array of characters to upper-case characters. + +// Declaration for the array of characters to upper-case characters. ABSL_DLL extern const char kToUpper[256]; - -// Declaration for the array of characters to lower-case characters. + +// Declaration for the array of characters to lower-case characters. ABSL_DLL extern const char kToLower[256]; - -} // namespace ascii_internal - -// ascii_isalpha() -// -// Determines whether the given character is an alphabetic character. -inline bool ascii_isalpha(unsigned char c) { - return (ascii_internal::kPropertyBits[c] & 0x01) != 0; -} - -// ascii_isalnum() -// -// Determines whether the given character is an alphanumeric character. -inline bool ascii_isalnum(unsigned char c) { - return (ascii_internal::kPropertyBits[c] & 0x04) != 0; -} - -// ascii_isspace() -// -// Determines whether the given character is a whitespace character (space, -// tab, vertical tab, formfeed, linefeed, or carriage return). -inline bool ascii_isspace(unsigned char c) { - return (ascii_internal::kPropertyBits[c] & 0x08) != 0; -} - -// ascii_ispunct() -// -// Determines whether the given character is a punctuation character. -inline bool ascii_ispunct(unsigned char c) { - return (ascii_internal::kPropertyBits[c] & 0x10) != 0; -} - -// ascii_isblank() -// -// Determines whether the given character is a blank character (tab or space). -inline bool ascii_isblank(unsigned char c) { - return (ascii_internal::kPropertyBits[c] & 0x20) != 0; -} - -// ascii_iscntrl() -// -// Determines whether the given character is a control character. -inline bool ascii_iscntrl(unsigned char c) { - return (ascii_internal::kPropertyBits[c] & 0x40) != 0; -} - -// ascii_isxdigit() -// -// Determines whether the given character can be represented as a hexadecimal -// digit character (i.e. {0-9} or {A-F}). -inline bool ascii_isxdigit(unsigned char c) { - return (ascii_internal::kPropertyBits[c] & 0x80) != 0; -} - -// ascii_isdigit() -// -// Determines whether the given character can be represented as a decimal -// digit character (i.e. {0-9}). -inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; } - -// ascii_isprint() -// -// Determines whether the given character is printable, including whitespace. -inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; } - -// ascii_isgraph() -// -// Determines whether the given character has a graphical representation. -inline bool ascii_isgraph(unsigned char c) { return c > 32 && c < 127; } - -// ascii_isupper() -// -// Determines whether the given character is uppercase. -inline bool ascii_isupper(unsigned char c) { return c >= 'A' && c <= 'Z'; } - -// ascii_islower() -// -// Determines whether the given character is lowercase. -inline bool ascii_islower(unsigned char c) { return c >= 'a' && c <= 'z'; } - -// ascii_isascii() -// -// Determines whether the given character is ASCII. -inline bool ascii_isascii(unsigned char c) { return c < 128; } - -// ascii_tolower() -// -// Returns an ASCII character, converting to lowercase if uppercase is -// passed. Note that character values > 127 are simply returned. -inline char ascii_tolower(unsigned char c) { - return ascii_internal::kToLower[c]; -} - -// Converts the characters in `s` to lowercase, changing the contents of `s`. + +} // namespace ascii_internal + +// ascii_isalpha() +// +// Determines whether the given character is an alphabetic character. +inline bool ascii_isalpha(unsigned char c) { + return (ascii_internal::kPropertyBits[c] & 0x01) != 0; +} + +// ascii_isalnum() +// +// Determines whether the given character is an alphanumeric character. +inline bool ascii_isalnum(unsigned char c) { + return (ascii_internal::kPropertyBits[c] & 0x04) != 0; +} + +// ascii_isspace() +// +// Determines whether the given character is a whitespace character (space, +// tab, vertical tab, formfeed, linefeed, or carriage return). +inline bool ascii_isspace(unsigned char c) { + return (ascii_internal::kPropertyBits[c] & 0x08) != 0; +} + +// ascii_ispunct() +// +// Determines whether the given character is a punctuation character. +inline bool ascii_ispunct(unsigned char c) { + return (ascii_internal::kPropertyBits[c] & 0x10) != 0; +} + +// ascii_isblank() +// +// Determines whether the given character is a blank character (tab or space). +inline bool ascii_isblank(unsigned char c) { + return (ascii_internal::kPropertyBits[c] & 0x20) != 0; +} + +// ascii_iscntrl() +// +// Determines whether the given character is a control character. +inline bool ascii_iscntrl(unsigned char c) { + return (ascii_internal::kPropertyBits[c] & 0x40) != 0; +} + +// ascii_isxdigit() +// +// Determines whether the given character can be represented as a hexadecimal +// digit character (i.e. {0-9} or {A-F}). +inline bool ascii_isxdigit(unsigned char c) { + return (ascii_internal::kPropertyBits[c] & 0x80) != 0; +} + +// ascii_isdigit() +// +// Determines whether the given character can be represented as a decimal +// digit character (i.e. {0-9}). +inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; } + +// ascii_isprint() +// +// Determines whether the given character is printable, including whitespace. +inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; } + +// ascii_isgraph() +// +// Determines whether the given character has a graphical representation. +inline bool ascii_isgraph(unsigned char c) { return c > 32 && c < 127; } + +// ascii_isupper() +// +// Determines whether the given character is uppercase. +inline bool ascii_isupper(unsigned char c) { return c >= 'A' && c <= 'Z'; } + +// ascii_islower() +// +// Determines whether the given character is lowercase. +inline bool ascii_islower(unsigned char c) { return c >= 'a' && c <= 'z'; } + +// ascii_isascii() +// +// Determines whether the given character is ASCII. +inline bool ascii_isascii(unsigned char c) { return c < 128; } + +// ascii_tolower() +// +// Returns an ASCII character, converting to lowercase if uppercase is +// passed. Note that character values > 127 are simply returned. +inline char ascii_tolower(unsigned char c) { + return ascii_internal::kToLower[c]; +} + +// Converts the characters in `s` to lowercase, changing the contents of `s`. void AsciiStrToLower(TString* s); - + // Creates a lowercase string from a given y_absl::string_view. ABSL_MUST_USE_RESULT inline TString AsciiStrToLower(y_absl::string_view s) { TString result(s); y_absl::AsciiStrToLower(&result); - return result; -} - -// ascii_toupper() -// -// Returns the ASCII character, converting to upper-case if lower-case is -// passed. Note that characters values > 127 are simply returned. -inline char ascii_toupper(unsigned char c) { - return ascii_internal::kToUpper[c]; -} - -// Converts the characters in `s` to uppercase, changing the contents of `s`. + return result; +} + +// ascii_toupper() +// +// Returns the ASCII character, converting to upper-case if lower-case is +// passed. Note that characters values > 127 are simply returned. +inline char ascii_toupper(unsigned char c) { + return ascii_internal::kToUpper[c]; +} + +// Converts the characters in `s` to uppercase, changing the contents of `s`. void AsciiStrToUpper(TString* s); - + // Creates an uppercase string from a given y_absl::string_view. ABSL_MUST_USE_RESULT inline TString AsciiStrToUpper(y_absl::string_view s) { TString result(s); y_absl::AsciiStrToUpper(&result); - return result; -} - + return result; +} + // Returns y_absl::string_view with whitespace stripped from the beginning of the -// given string_view. +// given string_view. ABSL_MUST_USE_RESULT inline y_absl::string_view StripLeadingAsciiWhitespace( y_absl::string_view str) { auto it = std::find_if_not(str.begin(), str.end(), y_absl::ascii_isspace); - return str.substr(it - str.begin()); -} - -// Strips in place whitespace from the beginning of the given string. + return str.substr(it - str.begin()); +} + +// Strips in place whitespace from the beginning of the given string. inline void StripLeadingAsciiWhitespace(TString* str) { auto it = std::find_if_not(str->cbegin(), str->cend(), y_absl::ascii_isspace); - str->erase(str->begin(), it); -} - + str->erase(str->begin(), it); +} + // Returns y_absl::string_view with whitespace stripped from the end of the given -// string_view. +// string_view. ABSL_MUST_USE_RESULT inline y_absl::string_view StripTrailingAsciiWhitespace( y_absl::string_view str) { auto it = std::find_if_not(str.rbegin(), str.rend(), y_absl::ascii_isspace); - return str.substr(0, str.rend() - it); -} - -// Strips in place whitespace from the end of the given string + return str.substr(0, str.rend() - it); +} + +// Strips in place whitespace from the end of the given string inline void StripTrailingAsciiWhitespace(TString* str) { auto it = std::find_if_not(str->rbegin(), str->rend(), y_absl::ascii_isspace); - str->erase(str->rend() - it); -} - + str->erase(str->rend() - it); +} + // Returns y_absl::string_view with whitespace stripped from both ends of the -// given string_view. +// given string_view. ABSL_MUST_USE_RESULT inline y_absl::string_view StripAsciiWhitespace( y_absl::string_view str) { - return StripTrailingAsciiWhitespace(StripLeadingAsciiWhitespace(str)); -} - -// Strips in place whitespace from both ends of the given string + return StripTrailingAsciiWhitespace(StripLeadingAsciiWhitespace(str)); +} + +// Strips in place whitespace from both ends of the given string inline void StripAsciiWhitespace(TString* str) { - StripTrailingAsciiWhitespace(str); - StripLeadingAsciiWhitespace(str); -} - -// Removes leading, trailing, and consecutive internal whitespace. + StripTrailingAsciiWhitespace(str); + StripLeadingAsciiWhitespace(str); +} + +// Removes leading, trailing, and consecutive internal whitespace. void RemoveExtraAsciiWhitespace(TString*); - + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_ASCII_H_ + +#endif // ABSL_STRINGS_ASCII_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.cc index 9515ca24dd..67f8b6d447 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.cc @@ -1,984 +1,984 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/charconv.h" - -#include <algorithm> -#include <cassert> -#include <cmath> -#include <cstring> - + +#include <algorithm> +#include <cassert> +#include <cmath> +#include <cstring> + #include "y_absl/base/casts.h" #include "y_absl/numeric/bits.h" #include "y_absl/numeric/int128.h" #include "y_absl/strings/internal/charconv_bigint.h" #include "y_absl/strings/internal/charconv_parse.h" - -// The macro ABSL_BIT_PACK_FLOATS is defined on x86-64, where IEEE floating -// point numbers have the same endianness in memory as a bitfield struct -// containing the corresponding parts. -// -// When set, we replace calls to ldexp() with manual bit packing, which is -// faster and is unaffected by floating point environment. -#ifdef ABSL_BIT_PACK_FLOATS -#error ABSL_BIT_PACK_FLOATS cannot be directly set -#elif defined(__x86_64__) || defined(_M_X64) -#define ABSL_BIT_PACK_FLOATS 1 -#endif - -// A note about subnormals: -// -// The code below talks about "normals" and "subnormals". A normal IEEE float -// has a fixed-width mantissa and power of two exponent. For example, a normal -// `double` has a 53-bit mantissa. Because the high bit is always 1, it is not -// stored in the representation. The implicit bit buys an extra bit of -// resolution in the datatype. -// -// The downside of this scheme is that there is a large gap between DBL_MIN and -// zero. (Large, at least, relative to the different between DBL_MIN and the -// next representable number). This gap is softened by the "subnormal" numbers, -// which have the same power-of-two exponent as DBL_MIN, but no implicit 53rd -// bit. An all-bits-zero exponent in the encoding represents subnormals. (Zero -// is represented as a subnormal with an all-bits-zero mantissa.) -// -// The code below, in calculations, represents the mantissa as a uint64_t. The -// end result normally has the 53rd bit set. It represents subnormals by using -// narrower mantissas. - + +// The macro ABSL_BIT_PACK_FLOATS is defined on x86-64, where IEEE floating +// point numbers have the same endianness in memory as a bitfield struct +// containing the corresponding parts. +// +// When set, we replace calls to ldexp() with manual bit packing, which is +// faster and is unaffected by floating point environment. +#ifdef ABSL_BIT_PACK_FLOATS +#error ABSL_BIT_PACK_FLOATS cannot be directly set +#elif defined(__x86_64__) || defined(_M_X64) +#define ABSL_BIT_PACK_FLOATS 1 +#endif + +// A note about subnormals: +// +// The code below talks about "normals" and "subnormals". A normal IEEE float +// has a fixed-width mantissa and power of two exponent. For example, a normal +// `double` has a 53-bit mantissa. Because the high bit is always 1, it is not +// stored in the representation. The implicit bit buys an extra bit of +// resolution in the datatype. +// +// The downside of this scheme is that there is a large gap between DBL_MIN and +// zero. (Large, at least, relative to the different between DBL_MIN and the +// next representable number). This gap is softened by the "subnormal" numbers, +// which have the same power-of-two exponent as DBL_MIN, but no implicit 53rd +// bit. An all-bits-zero exponent in the encoding represents subnormals. (Zero +// is represented as a subnormal with an all-bits-zero mantissa.) +// +// The code below, in calculations, represents the mantissa as a uint64_t. The +// end result normally has the 53rd bit set. It represents subnormals by using +// narrower mantissas. + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace { - -template <typename FloatType> -struct FloatTraits; - -template <> -struct FloatTraits<double> { - // The number of mantissa bits in the given float type. This includes the - // implied high bit. - static constexpr int kTargetMantissaBits = 53; - - // The largest supported IEEE exponent, in our integral mantissa - // representation. - // - // If `m` is the largest possible int kTargetMantissaBits bits wide, then - // m * 2**kMaxExponent is exactly equal to DBL_MAX. - static constexpr int kMaxExponent = 971; - - // The smallest supported IEEE normal exponent, in our integral mantissa - // representation. - // - // If `m` is the smallest possible int kTargetMantissaBits bits wide, then - // m * 2**kMinNormalExponent is exactly equal to DBL_MIN. - static constexpr int kMinNormalExponent = -1074; - - static double MakeNan(const char* tagp) { - // Support nan no matter which namespace it's in. Some platforms - // incorrectly don't put it in namespace std. - using namespace std; // NOLINT - return nan(tagp); - } - - // Builds a nonzero floating point number out of the provided parts. - // - // This is intended to do the same operation as ldexp(mantissa, exponent), - // but using purely integer math, to avoid -ffastmath and floating - // point environment issues. Using type punning is also faster. We fall back - // to ldexp on a per-platform basis for portability. - // - // `exponent` must be between kMinNormalExponent and kMaxExponent. - // - // `mantissa` must either be exactly kTargetMantissaBits wide, in which case - // a normal value is made, or it must be less narrow than that, in which case - // `exponent` must be exactly kMinNormalExponent, and a subnormal value is - // made. - static double Make(uint64_t mantissa, int exponent, bool sign) { -#ifndef ABSL_BIT_PACK_FLOATS - // Support ldexp no matter which namespace it's in. Some platforms - // incorrectly don't put it in namespace std. - using namespace std; // NOLINT - return sign ? -ldexp(mantissa, exponent) : ldexp(mantissa, exponent); -#else - constexpr uint64_t kMantissaMask = +namespace { + +template <typename FloatType> +struct FloatTraits; + +template <> +struct FloatTraits<double> { + // The number of mantissa bits in the given float type. This includes the + // implied high bit. + static constexpr int kTargetMantissaBits = 53; + + // The largest supported IEEE exponent, in our integral mantissa + // representation. + // + // If `m` is the largest possible int kTargetMantissaBits bits wide, then + // m * 2**kMaxExponent is exactly equal to DBL_MAX. + static constexpr int kMaxExponent = 971; + + // The smallest supported IEEE normal exponent, in our integral mantissa + // representation. + // + // If `m` is the smallest possible int kTargetMantissaBits bits wide, then + // m * 2**kMinNormalExponent is exactly equal to DBL_MIN. + static constexpr int kMinNormalExponent = -1074; + + static double MakeNan(const char* tagp) { + // Support nan no matter which namespace it's in. Some platforms + // incorrectly don't put it in namespace std. + using namespace std; // NOLINT + return nan(tagp); + } + + // Builds a nonzero floating point number out of the provided parts. + // + // This is intended to do the same operation as ldexp(mantissa, exponent), + // but using purely integer math, to avoid -ffastmath and floating + // point environment issues. Using type punning is also faster. We fall back + // to ldexp on a per-platform basis for portability. + // + // `exponent` must be between kMinNormalExponent and kMaxExponent. + // + // `mantissa` must either be exactly kTargetMantissaBits wide, in which case + // a normal value is made, or it must be less narrow than that, in which case + // `exponent` must be exactly kMinNormalExponent, and a subnormal value is + // made. + static double Make(uint64_t mantissa, int exponent, bool sign) { +#ifndef ABSL_BIT_PACK_FLOATS + // Support ldexp no matter which namespace it's in. Some platforms + // incorrectly don't put it in namespace std. + using namespace std; // NOLINT + return sign ? -ldexp(mantissa, exponent) : ldexp(mantissa, exponent); +#else + constexpr uint64_t kMantissaMask = (uint64_t{1} << (kTargetMantissaBits - 1)) - 1; - uint64_t dbl = static_cast<uint64_t>(sign) << 63; - if (mantissa > kMantissaMask) { - // Normal value. - // Adjust by 1023 for the exponent representation bias, and an additional - // 52 due to the implied decimal point in the IEEE mantissa represenation. - dbl += uint64_t{exponent + 1023u + kTargetMantissaBits - 1} << 52; - mantissa &= kMantissaMask; - } else { - // subnormal value - assert(exponent == kMinNormalExponent); - } - dbl += mantissa; + uint64_t dbl = static_cast<uint64_t>(sign) << 63; + if (mantissa > kMantissaMask) { + // Normal value. + // Adjust by 1023 for the exponent representation bias, and an additional + // 52 due to the implied decimal point in the IEEE mantissa represenation. + dbl += uint64_t{exponent + 1023u + kTargetMantissaBits - 1} << 52; + mantissa &= kMantissaMask; + } else { + // subnormal value + assert(exponent == kMinNormalExponent); + } + dbl += mantissa; return y_absl::bit_cast<double>(dbl); -#endif // ABSL_BIT_PACK_FLOATS - } -}; - -// Specialization of floating point traits for the `float` type. See the -// FloatTraits<double> specialization above for meaning of each of the following -// members and methods. -template <> -struct FloatTraits<float> { - static constexpr int kTargetMantissaBits = 24; - static constexpr int kMaxExponent = 104; - static constexpr int kMinNormalExponent = -149; - static float MakeNan(const char* tagp) { - // Support nanf no matter which namespace it's in. Some platforms - // incorrectly don't put it in namespace std. - using namespace std; // NOLINT - return nanf(tagp); - } - static float Make(uint32_t mantissa, int exponent, bool sign) { -#ifndef ABSL_BIT_PACK_FLOATS - // Support ldexpf no matter which namespace it's in. Some platforms - // incorrectly don't put it in namespace std. - using namespace std; // NOLINT - return sign ? -ldexpf(mantissa, exponent) : ldexpf(mantissa, exponent); -#else - constexpr uint32_t kMantissaMask = +#endif // ABSL_BIT_PACK_FLOATS + } +}; + +// Specialization of floating point traits for the `float` type. See the +// FloatTraits<double> specialization above for meaning of each of the following +// members and methods. +template <> +struct FloatTraits<float> { + static constexpr int kTargetMantissaBits = 24; + static constexpr int kMaxExponent = 104; + static constexpr int kMinNormalExponent = -149; + static float MakeNan(const char* tagp) { + // Support nanf no matter which namespace it's in. Some platforms + // incorrectly don't put it in namespace std. + using namespace std; // NOLINT + return nanf(tagp); + } + static float Make(uint32_t mantissa, int exponent, bool sign) { +#ifndef ABSL_BIT_PACK_FLOATS + // Support ldexpf no matter which namespace it's in. Some platforms + // incorrectly don't put it in namespace std. + using namespace std; // NOLINT + return sign ? -ldexpf(mantissa, exponent) : ldexpf(mantissa, exponent); +#else + constexpr uint32_t kMantissaMask = (uint32_t{1} << (kTargetMantissaBits - 1)) - 1; - uint32_t flt = static_cast<uint32_t>(sign) << 31; - if (mantissa > kMantissaMask) { - // Normal value. - // Adjust by 127 for the exponent representation bias, and an additional - // 23 due to the implied decimal point in the IEEE mantissa represenation. - flt += uint32_t{exponent + 127u + kTargetMantissaBits - 1} << 23; - mantissa &= kMantissaMask; - } else { - // subnormal value - assert(exponent == kMinNormalExponent); - } - flt += mantissa; + uint32_t flt = static_cast<uint32_t>(sign) << 31; + if (mantissa > kMantissaMask) { + // Normal value. + // Adjust by 127 for the exponent representation bias, and an additional + // 23 due to the implied decimal point in the IEEE mantissa represenation. + flt += uint32_t{exponent + 127u + kTargetMantissaBits - 1} << 23; + mantissa &= kMantissaMask; + } else { + // subnormal value + assert(exponent == kMinNormalExponent); + } + flt += mantissa; return y_absl::bit_cast<float>(flt); -#endif // ABSL_BIT_PACK_FLOATS - } -}; - -// Decimal-to-binary conversions require coercing powers of 10 into a mantissa -// and a power of 2. The two helper functions Power10Mantissa(n) and -// Power10Exponent(n) perform this task. Together, these represent a hand- -// rolled floating point value which is equal to or just less than 10**n. -// -// The return values satisfy two range guarantees: -// -// Power10Mantissa(n) * 2**Power10Exponent(n) <= 10**n -// < (Power10Mantissa(n) + 1) * 2**Power10Exponent(n) -// -// 2**63 <= Power10Mantissa(n) < 2**64. -// -// Lookups into the power-of-10 table must first check the Power10Overflow() and -// Power10Underflow() functions, to avoid out-of-bounds table access. -// -// Indexes into these tables are biased by -kPower10TableMin, and the table has -// values in the range [kPower10TableMin, kPower10TableMax]. -extern const uint64_t kPower10MantissaTable[]; -extern const int16_t kPower10ExponentTable[]; - -// The smallest allowed value for use with the Power10Mantissa() and -// Power10Exponent() functions below. (If a smaller exponent is needed in -// calculations, the end result is guaranteed to underflow.) -constexpr int kPower10TableMin = -342; - -// The largest allowed value for use with the Power10Mantissa() and -// Power10Exponent() functions below. (If a smaller exponent is needed in -// calculations, the end result is guaranteed to overflow.) -constexpr int kPower10TableMax = 308; - -uint64_t Power10Mantissa(int n) { - return kPower10MantissaTable[n - kPower10TableMin]; -} - -int Power10Exponent(int n) { - return kPower10ExponentTable[n - kPower10TableMin]; -} - -// Returns true if n is large enough that 10**n always results in an IEEE -// overflow. -bool Power10Overflow(int n) { return n > kPower10TableMax; } - -// Returns true if n is small enough that 10**n times a ParsedFloat mantissa -// always results in an IEEE underflow. -bool Power10Underflow(int n) { return n < kPower10TableMin; } - -// Returns true if Power10Mantissa(n) * 2**Power10Exponent(n) is exactly equal -// to 10**n numerically. Put another way, this returns true if there is no -// truncation error in Power10Mantissa(n). -bool Power10Exact(int n) { return n >= 0 && n <= 27; } - -// Sentinel exponent values for representing numbers too large or too close to -// zero to represent in a double. -constexpr int kOverflow = 99999; -constexpr int kUnderflow = -99999; - -// Struct representing the calculated conversion result of a positive (nonzero) -// floating point number. -// -// The calculated number is mantissa * 2**exponent (mantissa is treated as an -// integer.) `mantissa` is chosen to be the correct width for the IEEE float -// representation being calculated. (`mantissa` will always have the same bit -// width for normal values, and narrower bit widths for subnormals.) -// -// If the result of conversion was an underflow or overflow, exponent is set -// to kUnderflow or kOverflow. -struct CalculatedFloat { - uint64_t mantissa = 0; - int exponent = 0; -}; - -// Returns the bit width of the given uint128. (Equivalently, returns 128 -// minus the number of leading zero bits.) +#endif // ABSL_BIT_PACK_FLOATS + } +}; + +// Decimal-to-binary conversions require coercing powers of 10 into a mantissa +// and a power of 2. The two helper functions Power10Mantissa(n) and +// Power10Exponent(n) perform this task. Together, these represent a hand- +// rolled floating point value which is equal to or just less than 10**n. +// +// The return values satisfy two range guarantees: +// +// Power10Mantissa(n) * 2**Power10Exponent(n) <= 10**n +// < (Power10Mantissa(n) + 1) * 2**Power10Exponent(n) +// +// 2**63 <= Power10Mantissa(n) < 2**64. +// +// Lookups into the power-of-10 table must first check the Power10Overflow() and +// Power10Underflow() functions, to avoid out-of-bounds table access. +// +// Indexes into these tables are biased by -kPower10TableMin, and the table has +// values in the range [kPower10TableMin, kPower10TableMax]. +extern const uint64_t kPower10MantissaTable[]; +extern const int16_t kPower10ExponentTable[]; + +// The smallest allowed value for use with the Power10Mantissa() and +// Power10Exponent() functions below. (If a smaller exponent is needed in +// calculations, the end result is guaranteed to underflow.) +constexpr int kPower10TableMin = -342; + +// The largest allowed value for use with the Power10Mantissa() and +// Power10Exponent() functions below. (If a smaller exponent is needed in +// calculations, the end result is guaranteed to overflow.) +constexpr int kPower10TableMax = 308; + +uint64_t Power10Mantissa(int n) { + return kPower10MantissaTable[n - kPower10TableMin]; +} + +int Power10Exponent(int n) { + return kPower10ExponentTable[n - kPower10TableMin]; +} + +// Returns true if n is large enough that 10**n always results in an IEEE +// overflow. +bool Power10Overflow(int n) { return n > kPower10TableMax; } + +// Returns true if n is small enough that 10**n times a ParsedFloat mantissa +// always results in an IEEE underflow. +bool Power10Underflow(int n) { return n < kPower10TableMin; } + +// Returns true if Power10Mantissa(n) * 2**Power10Exponent(n) is exactly equal +// to 10**n numerically. Put another way, this returns true if there is no +// truncation error in Power10Mantissa(n). +bool Power10Exact(int n) { return n >= 0 && n <= 27; } + +// Sentinel exponent values for representing numbers too large or too close to +// zero to represent in a double. +constexpr int kOverflow = 99999; +constexpr int kUnderflow = -99999; + +// Struct representing the calculated conversion result of a positive (nonzero) +// floating point number. +// +// The calculated number is mantissa * 2**exponent (mantissa is treated as an +// integer.) `mantissa` is chosen to be the correct width for the IEEE float +// representation being calculated. (`mantissa` will always have the same bit +// width for normal values, and narrower bit widths for subnormals.) +// +// If the result of conversion was an underflow or overflow, exponent is set +// to kUnderflow or kOverflow. +struct CalculatedFloat { + uint64_t mantissa = 0; + int exponent = 0; +}; + +// Returns the bit width of the given uint128. (Equivalently, returns 128 +// minus the number of leading zero bits.) unsigned BitWidth(uint128 value) { - if (Uint128High64(value) == 0) { + if (Uint128High64(value) == 0) { return static_cast<unsigned>(bit_width(Uint128Low64(value))); - } + } return 128 - countl_zero(Uint128High64(value)); -} - -// Calculates how far to the right a mantissa needs to be shifted to create a -// properly adjusted mantissa for an IEEE floating point number. -// -// `mantissa_width` is the bit width of the mantissa to be shifted, and -// `binary_exponent` is the exponent of the number before the shift. -// -// This accounts for subnormal values, and will return a larger-than-normal -// shift if binary_exponent would otherwise be too low. -template <typename FloatType> -int NormalizedShiftSize(int mantissa_width, int binary_exponent) { - const int normal_shift = - mantissa_width - FloatTraits<FloatType>::kTargetMantissaBits; - const int minimum_shift = - FloatTraits<FloatType>::kMinNormalExponent - binary_exponent; - return std::max(normal_shift, minimum_shift); -} - -// Right shifts a uint128 so that it has the requested bit width. (The -// resulting value will have 128 - bit_width leading zeroes.) The initial -// `value` must be wider than the requested bit width. -// -// Returns the number of bits shifted. -int TruncateToBitWidth(int bit_width, uint128* value) { - const int current_bit_width = BitWidth(*value); - const int shift = current_bit_width - bit_width; - *value >>= shift; - return shift; -} - -// Checks if the given ParsedFloat represents one of the edge cases that are -// not dependent on number base: zero, infinity, or NaN. If so, sets *value -// the appropriate double, and returns true. -template <typename FloatType> -bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative, - FloatType* value) { - if (input.type == strings_internal::FloatType::kNan) { - // A bug in both clang and gcc would cause the compiler to optimize away the - // buffer we are building below. Declaring the buffer volatile avoids the - // issue, and has no measurable performance impact in microbenchmarks. - // - // https://bugs.llvm.org/show_bug.cgi?id=37778 - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86113 - constexpr ptrdiff_t kNanBufferSize = 128; - volatile char n_char_sequence[kNanBufferSize]; - if (input.subrange_begin == nullptr) { - n_char_sequence[0] = '\0'; - } else { - ptrdiff_t nan_size = input.subrange_end - input.subrange_begin; - nan_size = std::min(nan_size, kNanBufferSize - 1); - std::copy_n(input.subrange_begin, nan_size, n_char_sequence); - n_char_sequence[nan_size] = '\0'; - } - char* nan_argument = const_cast<char*>(n_char_sequence); - *value = negative ? -FloatTraits<FloatType>::MakeNan(nan_argument) - : FloatTraits<FloatType>::MakeNan(nan_argument); - return true; - } - if (input.type == strings_internal::FloatType::kInfinity) { - *value = negative ? -std::numeric_limits<FloatType>::infinity() - : std::numeric_limits<FloatType>::infinity(); - return true; - } - if (input.mantissa == 0) { - *value = negative ? -0.0 : 0.0; - return true; - } - return false; -} - -// Given a CalculatedFloat result of a from_chars conversion, generate the -// correct output values. -// -// CalculatedFloat can represent an underflow or overflow, in which case the -// error code in *result is set. Otherwise, the calculated floating point -// number is stored in *value. -template <typename FloatType> -void EncodeResult(const CalculatedFloat& calculated, bool negative, +} + +// Calculates how far to the right a mantissa needs to be shifted to create a +// properly adjusted mantissa for an IEEE floating point number. +// +// `mantissa_width` is the bit width of the mantissa to be shifted, and +// `binary_exponent` is the exponent of the number before the shift. +// +// This accounts for subnormal values, and will return a larger-than-normal +// shift if binary_exponent would otherwise be too low. +template <typename FloatType> +int NormalizedShiftSize(int mantissa_width, int binary_exponent) { + const int normal_shift = + mantissa_width - FloatTraits<FloatType>::kTargetMantissaBits; + const int minimum_shift = + FloatTraits<FloatType>::kMinNormalExponent - binary_exponent; + return std::max(normal_shift, minimum_shift); +} + +// Right shifts a uint128 so that it has the requested bit width. (The +// resulting value will have 128 - bit_width leading zeroes.) The initial +// `value` must be wider than the requested bit width. +// +// Returns the number of bits shifted. +int TruncateToBitWidth(int bit_width, uint128* value) { + const int current_bit_width = BitWidth(*value); + const int shift = current_bit_width - bit_width; + *value >>= shift; + return shift; +} + +// Checks if the given ParsedFloat represents one of the edge cases that are +// not dependent on number base: zero, infinity, or NaN. If so, sets *value +// the appropriate double, and returns true. +template <typename FloatType> +bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative, + FloatType* value) { + if (input.type == strings_internal::FloatType::kNan) { + // A bug in both clang and gcc would cause the compiler to optimize away the + // buffer we are building below. Declaring the buffer volatile avoids the + // issue, and has no measurable performance impact in microbenchmarks. + // + // https://bugs.llvm.org/show_bug.cgi?id=37778 + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86113 + constexpr ptrdiff_t kNanBufferSize = 128; + volatile char n_char_sequence[kNanBufferSize]; + if (input.subrange_begin == nullptr) { + n_char_sequence[0] = '\0'; + } else { + ptrdiff_t nan_size = input.subrange_end - input.subrange_begin; + nan_size = std::min(nan_size, kNanBufferSize - 1); + std::copy_n(input.subrange_begin, nan_size, n_char_sequence); + n_char_sequence[nan_size] = '\0'; + } + char* nan_argument = const_cast<char*>(n_char_sequence); + *value = negative ? -FloatTraits<FloatType>::MakeNan(nan_argument) + : FloatTraits<FloatType>::MakeNan(nan_argument); + return true; + } + if (input.type == strings_internal::FloatType::kInfinity) { + *value = negative ? -std::numeric_limits<FloatType>::infinity() + : std::numeric_limits<FloatType>::infinity(); + return true; + } + if (input.mantissa == 0) { + *value = negative ? -0.0 : 0.0; + return true; + } + return false; +} + +// Given a CalculatedFloat result of a from_chars conversion, generate the +// correct output values. +// +// CalculatedFloat can represent an underflow or overflow, in which case the +// error code in *result is set. Otherwise, the calculated floating point +// number is stored in *value. +template <typename FloatType> +void EncodeResult(const CalculatedFloat& calculated, bool negative, y_absl::from_chars_result* result, FloatType* value) { - if (calculated.exponent == kOverflow) { - result->ec = std::errc::result_out_of_range; - *value = negative ? -std::numeric_limits<FloatType>::max() - : std::numeric_limits<FloatType>::max(); - return; - } else if (calculated.mantissa == 0 || calculated.exponent == kUnderflow) { - result->ec = std::errc::result_out_of_range; - *value = negative ? -0.0 : 0.0; - return; - } - *value = FloatTraits<FloatType>::Make(calculated.mantissa, - calculated.exponent, negative); -} - -// Returns the given uint128 shifted to the right by `shift` bits, and rounds -// the remaining bits using round_to_nearest logic. The value is returned as a -// uint64_t, since this is the type used by this library for storing calculated -// floating point mantissas. -// -// It is expected that the width of the input value shifted by `shift` will -// be the correct bit-width for the target mantissa, which is strictly narrower -// than a uint64_t. -// -// If `input_exact` is false, then a nonzero error epsilon is assumed. For -// rounding purposes, the true value being rounded is strictly greater than the -// input value. The error may represent a single lost carry bit. -// -// When input_exact, shifted bits of the form 1000000... represent a tie, which -// is broken by rounding to even -- the rounding direction is chosen so the low -// bit of the returned value is 0. -// -// When !input_exact, shifted bits of the form 10000000... represent a value -// strictly greater than one half (due to the error epsilon), and so ties are -// always broken by rounding up. -// -// When !input_exact, shifted bits of the form 01111111... are uncertain; -// the true value may or may not be greater than 10000000..., due to the -// possible lost carry bit. The correct rounding direction is unknown. In this -// case, the result is rounded down, and `output_exact` is set to false. -// -// Zero and negative values of `shift` are accepted, in which case the word is -// shifted left, as necessary. -uint64_t ShiftRightAndRound(uint128 value, int shift, bool input_exact, - bool* output_exact) { - if (shift <= 0) { - *output_exact = input_exact; - return static_cast<uint64_t>(value << -shift); - } - if (shift >= 128) { - // Exponent is so small that we are shifting away all significant bits. - // Answer will not be representable, even as a subnormal, so return a zero - // mantissa (which represents underflow). - *output_exact = true; - return 0; - } - - *output_exact = true; - const uint128 shift_mask = (uint128(1) << shift) - 1; - const uint128 halfway_point = uint128(1) << (shift - 1); - - const uint128 shifted_bits = value & shift_mask; - value >>= shift; - if (shifted_bits > halfway_point) { - // Shifted bits greater than 10000... require rounding up. - return static_cast<uint64_t>(value + 1); - } - if (shifted_bits == halfway_point) { - // In exact mode, shifted bits of 10000... mean we're exactly halfway - // between two numbers, and we must round to even. So only round up if - // the low bit of `value` is set. - // - // In inexact mode, the nonzero error means the actual value is greater - // than the halfway point and we must alway round up. - if ((value & 1) == 1 || !input_exact) { - ++value; - } - return static_cast<uint64_t>(value); - } - if (!input_exact && shifted_bits == halfway_point - 1) { - // Rounding direction is unclear, due to error. - *output_exact = false; - } - // Otherwise, round down. - return static_cast<uint64_t>(value); -} - -// Checks if a floating point guess needs to be rounded up, using high precision -// math. -// -// `guess_mantissa` and `guess_exponent` represent a candidate guess for the -// number represented by `parsed_decimal`. -// -// The exact number represented by `parsed_decimal` must lie between the two -// numbers: -// A = `guess_mantissa * 2**guess_exponent` -// B = `(guess_mantissa + 1) * 2**guess_exponent` -// -// This function returns false if `A` is the better guess, and true if `B` is -// the better guess, with rounding ties broken by rounding to even. -bool MustRoundUp(uint64_t guess_mantissa, int guess_exponent, - const strings_internal::ParsedFloat& parsed_decimal) { - // 768 is the number of digits needed in the worst case. We could determine a - // better limit dynamically based on the value of parsed_decimal.exponent. - // This would optimize pathological input cases only. (Sane inputs won't have - // hundreds of digits of mantissa.) + if (calculated.exponent == kOverflow) { + result->ec = std::errc::result_out_of_range; + *value = negative ? -std::numeric_limits<FloatType>::max() + : std::numeric_limits<FloatType>::max(); + return; + } else if (calculated.mantissa == 0 || calculated.exponent == kUnderflow) { + result->ec = std::errc::result_out_of_range; + *value = negative ? -0.0 : 0.0; + return; + } + *value = FloatTraits<FloatType>::Make(calculated.mantissa, + calculated.exponent, negative); +} + +// Returns the given uint128 shifted to the right by `shift` bits, and rounds +// the remaining bits using round_to_nearest logic. The value is returned as a +// uint64_t, since this is the type used by this library for storing calculated +// floating point mantissas. +// +// It is expected that the width of the input value shifted by `shift` will +// be the correct bit-width for the target mantissa, which is strictly narrower +// than a uint64_t. +// +// If `input_exact` is false, then a nonzero error epsilon is assumed. For +// rounding purposes, the true value being rounded is strictly greater than the +// input value. The error may represent a single lost carry bit. +// +// When input_exact, shifted bits of the form 1000000... represent a tie, which +// is broken by rounding to even -- the rounding direction is chosen so the low +// bit of the returned value is 0. +// +// When !input_exact, shifted bits of the form 10000000... represent a value +// strictly greater than one half (due to the error epsilon), and so ties are +// always broken by rounding up. +// +// When !input_exact, shifted bits of the form 01111111... are uncertain; +// the true value may or may not be greater than 10000000..., due to the +// possible lost carry bit. The correct rounding direction is unknown. In this +// case, the result is rounded down, and `output_exact` is set to false. +// +// Zero and negative values of `shift` are accepted, in which case the word is +// shifted left, as necessary. +uint64_t ShiftRightAndRound(uint128 value, int shift, bool input_exact, + bool* output_exact) { + if (shift <= 0) { + *output_exact = input_exact; + return static_cast<uint64_t>(value << -shift); + } + if (shift >= 128) { + // Exponent is so small that we are shifting away all significant bits. + // Answer will not be representable, even as a subnormal, so return a zero + // mantissa (which represents underflow). + *output_exact = true; + return 0; + } + + *output_exact = true; + const uint128 shift_mask = (uint128(1) << shift) - 1; + const uint128 halfway_point = uint128(1) << (shift - 1); + + const uint128 shifted_bits = value & shift_mask; + value >>= shift; + if (shifted_bits > halfway_point) { + // Shifted bits greater than 10000... require rounding up. + return static_cast<uint64_t>(value + 1); + } + if (shifted_bits == halfway_point) { + // In exact mode, shifted bits of 10000... mean we're exactly halfway + // between two numbers, and we must round to even. So only round up if + // the low bit of `value` is set. + // + // In inexact mode, the nonzero error means the actual value is greater + // than the halfway point and we must alway round up. + if ((value & 1) == 1 || !input_exact) { + ++value; + } + return static_cast<uint64_t>(value); + } + if (!input_exact && shifted_bits == halfway_point - 1) { + // Rounding direction is unclear, due to error. + *output_exact = false; + } + // Otherwise, round down. + return static_cast<uint64_t>(value); +} + +// Checks if a floating point guess needs to be rounded up, using high precision +// math. +// +// `guess_mantissa` and `guess_exponent` represent a candidate guess for the +// number represented by `parsed_decimal`. +// +// The exact number represented by `parsed_decimal` must lie between the two +// numbers: +// A = `guess_mantissa * 2**guess_exponent` +// B = `(guess_mantissa + 1) * 2**guess_exponent` +// +// This function returns false if `A` is the better guess, and true if `B` is +// the better guess, with rounding ties broken by rounding to even. +bool MustRoundUp(uint64_t guess_mantissa, int guess_exponent, + const strings_internal::ParsedFloat& parsed_decimal) { + // 768 is the number of digits needed in the worst case. We could determine a + // better limit dynamically based on the value of parsed_decimal.exponent. + // This would optimize pathological input cases only. (Sane inputs won't have + // hundreds of digits of mantissa.) y_absl::strings_internal::BigUnsigned<84> exact_mantissa; - int exact_exponent = exact_mantissa.ReadFloatMantissa(parsed_decimal, 768); - - // Adjust the `guess` arguments to be halfway between A and B. - guess_mantissa = guess_mantissa * 2 + 1; - guess_exponent -= 1; - - // In our comparison: - // lhs = exact = exact_mantissa * 10**exact_exponent - // = exact_mantissa * 5**exact_exponent * 2**exact_exponent - // rhs = guess = guess_mantissa * 2**guess_exponent - // - // Because we are doing integer math, we can't directly deal with negative - // exponents. We instead move these to the other side of the inequality. + int exact_exponent = exact_mantissa.ReadFloatMantissa(parsed_decimal, 768); + + // Adjust the `guess` arguments to be halfway between A and B. + guess_mantissa = guess_mantissa * 2 + 1; + guess_exponent -= 1; + + // In our comparison: + // lhs = exact = exact_mantissa * 10**exact_exponent + // = exact_mantissa * 5**exact_exponent * 2**exact_exponent + // rhs = guess = guess_mantissa * 2**guess_exponent + // + // Because we are doing integer math, we can't directly deal with negative + // exponents. We instead move these to the other side of the inequality. y_absl::strings_internal::BigUnsigned<84>& lhs = exact_mantissa; - int comparison; - if (exact_exponent >= 0) { - lhs.MultiplyByFiveToTheNth(exact_exponent); + int comparison; + if (exact_exponent >= 0) { + lhs.MultiplyByFiveToTheNth(exact_exponent); y_absl::strings_internal::BigUnsigned<84> rhs(guess_mantissa); - // There are powers of 2 on both sides of the inequality; reduce this to - // a single bit-shift. - if (exact_exponent > guess_exponent) { - lhs.ShiftLeft(exact_exponent - guess_exponent); - } else { - rhs.ShiftLeft(guess_exponent - exact_exponent); - } - comparison = Compare(lhs, rhs); - } else { - // Move the power of 5 to the other side of the equation, giving us: - // lhs = exact_mantissa * 2**exact_exponent - // rhs = guess_mantissa * 5**(-exact_exponent) * 2**guess_exponent + // There are powers of 2 on both sides of the inequality; reduce this to + // a single bit-shift. + if (exact_exponent > guess_exponent) { + lhs.ShiftLeft(exact_exponent - guess_exponent); + } else { + rhs.ShiftLeft(guess_exponent - exact_exponent); + } + comparison = Compare(lhs, rhs); + } else { + // Move the power of 5 to the other side of the equation, giving us: + // lhs = exact_mantissa * 2**exact_exponent + // rhs = guess_mantissa * 5**(-exact_exponent) * 2**guess_exponent y_absl::strings_internal::BigUnsigned<84> rhs = y_absl::strings_internal::BigUnsigned<84>::FiveToTheNth(-exact_exponent); - rhs.MultiplyBy(guess_mantissa); - if (exact_exponent > guess_exponent) { - lhs.ShiftLeft(exact_exponent - guess_exponent); - } else { - rhs.ShiftLeft(guess_exponent - exact_exponent); - } - comparison = Compare(lhs, rhs); - } - if (comparison < 0) { - return false; - } else if (comparison > 0) { - return true; - } else { - // When lhs == rhs, the decimal input is exactly between A and B. - // Round towards even -- round up only if the low bit of the initial - // `guess_mantissa` was a 1. We shifted guess_mantissa left 1 bit at - // the beginning of this function, so test the 2nd bit here. - return (guess_mantissa & 2) == 2; - } -} - -// Constructs a CalculatedFloat from a given mantissa and exponent, but -// with the following normalizations applied: -// -// If rounding has caused mantissa to increase just past the allowed bit -// width, shift and adjust exponent. -// -// If exponent is too high, sets kOverflow. -// -// If mantissa is zero (representing a non-zero value not representable, even -// as a subnormal), sets kUnderflow. -template <typename FloatType> -CalculatedFloat CalculatedFloatFromRawValues(uint64_t mantissa, int exponent) { - CalculatedFloat result; + rhs.MultiplyBy(guess_mantissa); + if (exact_exponent > guess_exponent) { + lhs.ShiftLeft(exact_exponent - guess_exponent); + } else { + rhs.ShiftLeft(guess_exponent - exact_exponent); + } + comparison = Compare(lhs, rhs); + } + if (comparison < 0) { + return false; + } else if (comparison > 0) { + return true; + } else { + // When lhs == rhs, the decimal input is exactly between A and B. + // Round towards even -- round up only if the low bit of the initial + // `guess_mantissa` was a 1. We shifted guess_mantissa left 1 bit at + // the beginning of this function, so test the 2nd bit here. + return (guess_mantissa & 2) == 2; + } +} + +// Constructs a CalculatedFloat from a given mantissa and exponent, but +// with the following normalizations applied: +// +// If rounding has caused mantissa to increase just past the allowed bit +// width, shift and adjust exponent. +// +// If exponent is too high, sets kOverflow. +// +// If mantissa is zero (representing a non-zero value not representable, even +// as a subnormal), sets kUnderflow. +template <typename FloatType> +CalculatedFloat CalculatedFloatFromRawValues(uint64_t mantissa, int exponent) { + CalculatedFloat result; if (mantissa == uint64_t{1} << FloatTraits<FloatType>::kTargetMantissaBits) { - mantissa >>= 1; - exponent += 1; - } - if (exponent > FloatTraits<FloatType>::kMaxExponent) { - result.exponent = kOverflow; - } else if (mantissa == 0) { - result.exponent = kUnderflow; - } else { - result.exponent = exponent; - result.mantissa = mantissa; - } - return result; -} - -template <typename FloatType> -CalculatedFloat CalculateFromParsedHexadecimal( - const strings_internal::ParsedFloat& parsed_hex) { - uint64_t mantissa = parsed_hex.mantissa; - int exponent = parsed_hex.exponent; + mantissa >>= 1; + exponent += 1; + } + if (exponent > FloatTraits<FloatType>::kMaxExponent) { + result.exponent = kOverflow; + } else if (mantissa == 0) { + result.exponent = kUnderflow; + } else { + result.exponent = exponent; + result.mantissa = mantissa; + } + return result; +} + +template <typename FloatType> +CalculatedFloat CalculateFromParsedHexadecimal( + const strings_internal::ParsedFloat& parsed_hex) { + uint64_t mantissa = parsed_hex.mantissa; + int exponent = parsed_hex.exponent; auto mantissa_width = static_cast<unsigned>(bit_width(mantissa)); - const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent); - bool result_exact; - exponent += shift; - mantissa = ShiftRightAndRound(mantissa, shift, - /* input exact= */ true, &result_exact); - // ParseFloat handles rounding in the hexadecimal case, so we don't have to - // check `result_exact` here. - return CalculatedFloatFromRawValues<FloatType>(mantissa, exponent); -} - -template <typename FloatType> -CalculatedFloat CalculateFromParsedDecimal( - const strings_internal::ParsedFloat& parsed_decimal) { - CalculatedFloat result; - - // Large or small enough decimal exponents will always result in overflow - // or underflow. - if (Power10Underflow(parsed_decimal.exponent)) { - result.exponent = kUnderflow; - return result; - } else if (Power10Overflow(parsed_decimal.exponent)) { - result.exponent = kOverflow; - return result; - } - - // Otherwise convert our power of 10 into a power of 2 times an integer - // mantissa, and multiply this by our parsed decimal mantissa. - uint128 wide_binary_mantissa = parsed_decimal.mantissa; - wide_binary_mantissa *= Power10Mantissa(parsed_decimal.exponent); - int binary_exponent = Power10Exponent(parsed_decimal.exponent); - - // Discard bits that are inaccurate due to truncation error. The magic - // `mantissa_width` constants below are justified in - // https://abseil.io/about/design/charconv. They represent the number of bits - // in `wide_binary_mantissa` that are guaranteed to be unaffected by error - // propagation. - bool mantissa_exact; - int mantissa_width; - if (parsed_decimal.subrange_begin) { - // Truncated mantissa - mantissa_width = 58; - mantissa_exact = false; - binary_exponent += - TruncateToBitWidth(mantissa_width, &wide_binary_mantissa); - } else if (!Power10Exact(parsed_decimal.exponent)) { - // Exact mantissa, truncated power of ten - mantissa_width = 63; - mantissa_exact = false; - binary_exponent += - TruncateToBitWidth(mantissa_width, &wide_binary_mantissa); - } else { - // Product is exact - mantissa_width = BitWidth(wide_binary_mantissa); - mantissa_exact = true; - } - - // Shift into an FloatType-sized mantissa, and round to nearest. - const int shift = - NormalizedShiftSize<FloatType>(mantissa_width, binary_exponent); - bool result_exact; - binary_exponent += shift; - uint64_t binary_mantissa = ShiftRightAndRound(wide_binary_mantissa, shift, - mantissa_exact, &result_exact); - if (!result_exact) { - // We could not determine the rounding direction using int128 math. Use - // full resolution math instead. - if (MustRoundUp(binary_mantissa, binary_exponent, parsed_decimal)) { - binary_mantissa += 1; - } - } - - return CalculatedFloatFromRawValues<FloatType>(binary_mantissa, - binary_exponent); -} - -template <typename FloatType> -from_chars_result FromCharsImpl(const char* first, const char* last, - FloatType& value, chars_format fmt_flags) { - from_chars_result result; - result.ptr = first; // overwritten on successful parse - result.ec = std::errc(); - - bool negative = false; - if (first != last && *first == '-') { - ++first; - negative = true; - } - // If the `hex` flag is *not* set, then we will accept a 0x prefix and try - // to parse a hexadecimal float. - if ((fmt_flags & chars_format::hex) == chars_format{} && last - first >= 2 && - *first == '0' && (first[1] == 'x' || first[1] == 'X')) { - const char* hex_first = first + 2; - strings_internal::ParsedFloat hex_parse = - strings_internal::ParseFloat<16>(hex_first, last, fmt_flags); - if (hex_parse.end == nullptr || - hex_parse.type != strings_internal::FloatType::kNumber) { - // Either we failed to parse a hex float after the "0x", or we read - // "0xinf" or "0xnan" which we don't want to match. - // + const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent); + bool result_exact; + exponent += shift; + mantissa = ShiftRightAndRound(mantissa, shift, + /* input exact= */ true, &result_exact); + // ParseFloat handles rounding in the hexadecimal case, so we don't have to + // check `result_exact` here. + return CalculatedFloatFromRawValues<FloatType>(mantissa, exponent); +} + +template <typename FloatType> +CalculatedFloat CalculateFromParsedDecimal( + const strings_internal::ParsedFloat& parsed_decimal) { + CalculatedFloat result; + + // Large or small enough decimal exponents will always result in overflow + // or underflow. + if (Power10Underflow(parsed_decimal.exponent)) { + result.exponent = kUnderflow; + return result; + } else if (Power10Overflow(parsed_decimal.exponent)) { + result.exponent = kOverflow; + return result; + } + + // Otherwise convert our power of 10 into a power of 2 times an integer + // mantissa, and multiply this by our parsed decimal mantissa. + uint128 wide_binary_mantissa = parsed_decimal.mantissa; + wide_binary_mantissa *= Power10Mantissa(parsed_decimal.exponent); + int binary_exponent = Power10Exponent(parsed_decimal.exponent); + + // Discard bits that are inaccurate due to truncation error. The magic + // `mantissa_width` constants below are justified in + // https://abseil.io/about/design/charconv. They represent the number of bits + // in `wide_binary_mantissa` that are guaranteed to be unaffected by error + // propagation. + bool mantissa_exact; + int mantissa_width; + if (parsed_decimal.subrange_begin) { + // Truncated mantissa + mantissa_width = 58; + mantissa_exact = false; + binary_exponent += + TruncateToBitWidth(mantissa_width, &wide_binary_mantissa); + } else if (!Power10Exact(parsed_decimal.exponent)) { + // Exact mantissa, truncated power of ten + mantissa_width = 63; + mantissa_exact = false; + binary_exponent += + TruncateToBitWidth(mantissa_width, &wide_binary_mantissa); + } else { + // Product is exact + mantissa_width = BitWidth(wide_binary_mantissa); + mantissa_exact = true; + } + + // Shift into an FloatType-sized mantissa, and round to nearest. + const int shift = + NormalizedShiftSize<FloatType>(mantissa_width, binary_exponent); + bool result_exact; + binary_exponent += shift; + uint64_t binary_mantissa = ShiftRightAndRound(wide_binary_mantissa, shift, + mantissa_exact, &result_exact); + if (!result_exact) { + // We could not determine the rounding direction using int128 math. Use + // full resolution math instead. + if (MustRoundUp(binary_mantissa, binary_exponent, parsed_decimal)) { + binary_mantissa += 1; + } + } + + return CalculatedFloatFromRawValues<FloatType>(binary_mantissa, + binary_exponent); +} + +template <typename FloatType> +from_chars_result FromCharsImpl(const char* first, const char* last, + FloatType& value, chars_format fmt_flags) { + from_chars_result result; + result.ptr = first; // overwritten on successful parse + result.ec = std::errc(); + + bool negative = false; + if (first != last && *first == '-') { + ++first; + negative = true; + } + // If the `hex` flag is *not* set, then we will accept a 0x prefix and try + // to parse a hexadecimal float. + if ((fmt_flags & chars_format::hex) == chars_format{} && last - first >= 2 && + *first == '0' && (first[1] == 'x' || first[1] == 'X')) { + const char* hex_first = first + 2; + strings_internal::ParsedFloat hex_parse = + strings_internal::ParseFloat<16>(hex_first, last, fmt_flags); + if (hex_parse.end == nullptr || + hex_parse.type != strings_internal::FloatType::kNumber) { + // Either we failed to parse a hex float after the "0x", or we read + // "0xinf" or "0xnan" which we don't want to match. + // // However, a string that begins with "0x" also begins with "0", which - // is normally a valid match for the number zero. So we want these - // strings to match zero unless fmt_flags is `scientific`. (This flag + // is normally a valid match for the number zero. So we want these + // strings to match zero unless fmt_flags is `scientific`. (This flag // means an exponent is required, which the string "0" does not have.) - if (fmt_flags == chars_format::scientific) { - result.ec = std::errc::invalid_argument; - } else { - result.ptr = first + 1; - value = negative ? -0.0 : 0.0; - } - return result; - } - // We matched a value. - result.ptr = hex_parse.end; - if (HandleEdgeCase(hex_parse, negative, &value)) { - return result; - } - CalculatedFloat calculated = - CalculateFromParsedHexadecimal<FloatType>(hex_parse); - EncodeResult(calculated, negative, &result, &value); - return result; - } - // Otherwise, we choose the number base based on the flags. - if ((fmt_flags & chars_format::hex) == chars_format::hex) { - strings_internal::ParsedFloat hex_parse = - strings_internal::ParseFloat<16>(first, last, fmt_flags); - if (hex_parse.end == nullptr) { - result.ec = std::errc::invalid_argument; - return result; - } - result.ptr = hex_parse.end; - if (HandleEdgeCase(hex_parse, negative, &value)) { - return result; - } - CalculatedFloat calculated = - CalculateFromParsedHexadecimal<FloatType>(hex_parse); - EncodeResult(calculated, negative, &result, &value); - return result; - } else { - strings_internal::ParsedFloat decimal_parse = - strings_internal::ParseFloat<10>(first, last, fmt_flags); - if (decimal_parse.end == nullptr) { - result.ec = std::errc::invalid_argument; - return result; - } - result.ptr = decimal_parse.end; - if (HandleEdgeCase(decimal_parse, negative, &value)) { - return result; - } - CalculatedFloat calculated = - CalculateFromParsedDecimal<FloatType>(decimal_parse); - EncodeResult(calculated, negative, &result, &value); - return result; - } -} -} // namespace - -from_chars_result from_chars(const char* first, const char* last, double& value, - chars_format fmt) { - return FromCharsImpl(first, last, value, fmt); -} - -from_chars_result from_chars(const char* first, const char* last, float& value, - chars_format fmt) { - return FromCharsImpl(first, last, value, fmt); -} - -namespace { - -// Table of powers of 10, from kPower10TableMin to kPower10TableMax. -// -// kPower10MantissaTable[i - kPower10TableMin] stores the 64-bit mantissa (high -// bit always on), and kPower10ExponentTable[i - kPower10TableMin] stores the -// power-of-two exponent. For a given number i, this gives the unique mantissa -// and exponent such that mantissa * 2**exponent <= 10**i < (mantissa + 1) * -// 2**exponent. - -const uint64_t kPower10MantissaTable[] = { - 0xeef453d6923bd65aU, 0x9558b4661b6565f8U, 0xbaaee17fa23ebf76U, - 0xe95a99df8ace6f53U, 0x91d8a02bb6c10594U, 0xb64ec836a47146f9U, - 0xe3e27a444d8d98b7U, 0x8e6d8c6ab0787f72U, 0xb208ef855c969f4fU, - 0xde8b2b66b3bc4723U, 0x8b16fb203055ac76U, 0xaddcb9e83c6b1793U, - 0xd953e8624b85dd78U, 0x87d4713d6f33aa6bU, 0xa9c98d8ccb009506U, - 0xd43bf0effdc0ba48U, 0x84a57695fe98746dU, 0xa5ced43b7e3e9188U, - 0xcf42894a5dce35eaU, 0x818995ce7aa0e1b2U, 0xa1ebfb4219491a1fU, - 0xca66fa129f9b60a6U, 0xfd00b897478238d0U, 0x9e20735e8cb16382U, - 0xc5a890362fddbc62U, 0xf712b443bbd52b7bU, 0x9a6bb0aa55653b2dU, - 0xc1069cd4eabe89f8U, 0xf148440a256e2c76U, 0x96cd2a865764dbcaU, - 0xbc807527ed3e12bcU, 0xeba09271e88d976bU, 0x93445b8731587ea3U, - 0xb8157268fdae9e4cU, 0xe61acf033d1a45dfU, 0x8fd0c16206306babU, - 0xb3c4f1ba87bc8696U, 0xe0b62e2929aba83cU, 0x8c71dcd9ba0b4925U, - 0xaf8e5410288e1b6fU, 0xdb71e91432b1a24aU, 0x892731ac9faf056eU, - 0xab70fe17c79ac6caU, 0xd64d3d9db981787dU, 0x85f0468293f0eb4eU, - 0xa76c582338ed2621U, 0xd1476e2c07286faaU, 0x82cca4db847945caU, - 0xa37fce126597973cU, 0xcc5fc196fefd7d0cU, 0xff77b1fcbebcdc4fU, - 0x9faacf3df73609b1U, 0xc795830d75038c1dU, 0xf97ae3d0d2446f25U, - 0x9becce62836ac577U, 0xc2e801fb244576d5U, 0xf3a20279ed56d48aU, - 0x9845418c345644d6U, 0xbe5691ef416bd60cU, 0xedec366b11c6cb8fU, - 0x94b3a202eb1c3f39U, 0xb9e08a83a5e34f07U, 0xe858ad248f5c22c9U, - 0x91376c36d99995beU, 0xb58547448ffffb2dU, 0xe2e69915b3fff9f9U, - 0x8dd01fad907ffc3bU, 0xb1442798f49ffb4aU, 0xdd95317f31c7fa1dU, - 0x8a7d3eef7f1cfc52U, 0xad1c8eab5ee43b66U, 0xd863b256369d4a40U, - 0x873e4f75e2224e68U, 0xa90de3535aaae202U, 0xd3515c2831559a83U, - 0x8412d9991ed58091U, 0xa5178fff668ae0b6U, 0xce5d73ff402d98e3U, - 0x80fa687f881c7f8eU, 0xa139029f6a239f72U, 0xc987434744ac874eU, - 0xfbe9141915d7a922U, 0x9d71ac8fada6c9b5U, 0xc4ce17b399107c22U, - 0xf6019da07f549b2bU, 0x99c102844f94e0fbU, 0xc0314325637a1939U, - 0xf03d93eebc589f88U, 0x96267c7535b763b5U, 0xbbb01b9283253ca2U, - 0xea9c227723ee8bcbU, 0x92a1958a7675175fU, 0xb749faed14125d36U, - 0xe51c79a85916f484U, 0x8f31cc0937ae58d2U, 0xb2fe3f0b8599ef07U, - 0xdfbdcece67006ac9U, 0x8bd6a141006042bdU, 0xaecc49914078536dU, - 0xda7f5bf590966848U, 0x888f99797a5e012dU, 0xaab37fd7d8f58178U, - 0xd5605fcdcf32e1d6U, 0x855c3be0a17fcd26U, 0xa6b34ad8c9dfc06fU, - 0xd0601d8efc57b08bU, 0x823c12795db6ce57U, 0xa2cb1717b52481edU, - 0xcb7ddcdda26da268U, 0xfe5d54150b090b02U, 0x9efa548d26e5a6e1U, - 0xc6b8e9b0709f109aU, 0xf867241c8cc6d4c0U, 0x9b407691d7fc44f8U, - 0xc21094364dfb5636U, 0xf294b943e17a2bc4U, 0x979cf3ca6cec5b5aU, - 0xbd8430bd08277231U, 0xece53cec4a314ebdU, 0x940f4613ae5ed136U, - 0xb913179899f68584U, 0xe757dd7ec07426e5U, 0x9096ea6f3848984fU, - 0xb4bca50b065abe63U, 0xe1ebce4dc7f16dfbU, 0x8d3360f09cf6e4bdU, - 0xb080392cc4349decU, 0xdca04777f541c567U, 0x89e42caaf9491b60U, - 0xac5d37d5b79b6239U, 0xd77485cb25823ac7U, 0x86a8d39ef77164bcU, - 0xa8530886b54dbdebU, 0xd267caa862a12d66U, 0x8380dea93da4bc60U, - 0xa46116538d0deb78U, 0xcd795be870516656U, 0x806bd9714632dff6U, - 0xa086cfcd97bf97f3U, 0xc8a883c0fdaf7df0U, 0xfad2a4b13d1b5d6cU, - 0x9cc3a6eec6311a63U, 0xc3f490aa77bd60fcU, 0xf4f1b4d515acb93bU, - 0x991711052d8bf3c5U, 0xbf5cd54678eef0b6U, 0xef340a98172aace4U, - 0x9580869f0e7aac0eU, 0xbae0a846d2195712U, 0xe998d258869facd7U, - 0x91ff83775423cc06U, 0xb67f6455292cbf08U, 0xe41f3d6a7377eecaU, - 0x8e938662882af53eU, 0xb23867fb2a35b28dU, 0xdec681f9f4c31f31U, - 0x8b3c113c38f9f37eU, 0xae0b158b4738705eU, 0xd98ddaee19068c76U, - 0x87f8a8d4cfa417c9U, 0xa9f6d30a038d1dbcU, 0xd47487cc8470652bU, - 0x84c8d4dfd2c63f3bU, 0xa5fb0a17c777cf09U, 0xcf79cc9db955c2ccU, - 0x81ac1fe293d599bfU, 0xa21727db38cb002fU, 0xca9cf1d206fdc03bU, - 0xfd442e4688bd304aU, 0x9e4a9cec15763e2eU, 0xc5dd44271ad3cdbaU, - 0xf7549530e188c128U, 0x9a94dd3e8cf578b9U, 0xc13a148e3032d6e7U, - 0xf18899b1bc3f8ca1U, 0x96f5600f15a7b7e5U, 0xbcb2b812db11a5deU, - 0xebdf661791d60f56U, 0x936b9fcebb25c995U, 0xb84687c269ef3bfbU, - 0xe65829b3046b0afaU, 0x8ff71a0fe2c2e6dcU, 0xb3f4e093db73a093U, - 0xe0f218b8d25088b8U, 0x8c974f7383725573U, 0xafbd2350644eeacfU, - 0xdbac6c247d62a583U, 0x894bc396ce5da772U, 0xab9eb47c81f5114fU, - 0xd686619ba27255a2U, 0x8613fd0145877585U, 0xa798fc4196e952e7U, - 0xd17f3b51fca3a7a0U, 0x82ef85133de648c4U, 0xa3ab66580d5fdaf5U, - 0xcc963fee10b7d1b3U, 0xffbbcfe994e5c61fU, 0x9fd561f1fd0f9bd3U, - 0xc7caba6e7c5382c8U, 0xf9bd690a1b68637bU, 0x9c1661a651213e2dU, - 0xc31bfa0fe5698db8U, 0xf3e2f893dec3f126U, 0x986ddb5c6b3a76b7U, - 0xbe89523386091465U, 0xee2ba6c0678b597fU, 0x94db483840b717efU, - 0xba121a4650e4ddebU, 0xe896a0d7e51e1566U, 0x915e2486ef32cd60U, - 0xb5b5ada8aaff80b8U, 0xe3231912d5bf60e6U, 0x8df5efabc5979c8fU, - 0xb1736b96b6fd83b3U, 0xddd0467c64bce4a0U, 0x8aa22c0dbef60ee4U, - 0xad4ab7112eb3929dU, 0xd89d64d57a607744U, 0x87625f056c7c4a8bU, - 0xa93af6c6c79b5d2dU, 0xd389b47879823479U, 0x843610cb4bf160cbU, - 0xa54394fe1eedb8feU, 0xce947a3da6a9273eU, 0x811ccc668829b887U, - 0xa163ff802a3426a8U, 0xc9bcff6034c13052U, 0xfc2c3f3841f17c67U, - 0x9d9ba7832936edc0U, 0xc5029163f384a931U, 0xf64335bcf065d37dU, - 0x99ea0196163fa42eU, 0xc06481fb9bcf8d39U, 0xf07da27a82c37088U, - 0x964e858c91ba2655U, 0xbbe226efb628afeaU, 0xeadab0aba3b2dbe5U, - 0x92c8ae6b464fc96fU, 0xb77ada0617e3bbcbU, 0xe55990879ddcaabdU, - 0x8f57fa54c2a9eab6U, 0xb32df8e9f3546564U, 0xdff9772470297ebdU, - 0x8bfbea76c619ef36U, 0xaefae51477a06b03U, 0xdab99e59958885c4U, - 0x88b402f7fd75539bU, 0xaae103b5fcd2a881U, 0xd59944a37c0752a2U, - 0x857fcae62d8493a5U, 0xa6dfbd9fb8e5b88eU, 0xd097ad07a71f26b2U, - 0x825ecc24c873782fU, 0xa2f67f2dfa90563bU, 0xcbb41ef979346bcaU, - 0xfea126b7d78186bcU, 0x9f24b832e6b0f436U, 0xc6ede63fa05d3143U, - 0xf8a95fcf88747d94U, 0x9b69dbe1b548ce7cU, 0xc24452da229b021bU, - 0xf2d56790ab41c2a2U, 0x97c560ba6b0919a5U, 0xbdb6b8e905cb600fU, - 0xed246723473e3813U, 0x9436c0760c86e30bU, 0xb94470938fa89bceU, - 0xe7958cb87392c2c2U, 0x90bd77f3483bb9b9U, 0xb4ecd5f01a4aa828U, - 0xe2280b6c20dd5232U, 0x8d590723948a535fU, 0xb0af48ec79ace837U, - 0xdcdb1b2798182244U, 0x8a08f0f8bf0f156bU, 0xac8b2d36eed2dac5U, - 0xd7adf884aa879177U, 0x86ccbb52ea94baeaU, 0xa87fea27a539e9a5U, - 0xd29fe4b18e88640eU, 0x83a3eeeef9153e89U, 0xa48ceaaab75a8e2bU, - 0xcdb02555653131b6U, 0x808e17555f3ebf11U, 0xa0b19d2ab70e6ed6U, - 0xc8de047564d20a8bU, 0xfb158592be068d2eU, 0x9ced737bb6c4183dU, - 0xc428d05aa4751e4cU, 0xf53304714d9265dfU, 0x993fe2c6d07b7fabU, - 0xbf8fdb78849a5f96U, 0xef73d256a5c0f77cU, 0x95a8637627989aadU, - 0xbb127c53b17ec159U, 0xe9d71b689dde71afU, 0x9226712162ab070dU, - 0xb6b00d69bb55c8d1U, 0xe45c10c42a2b3b05U, 0x8eb98a7a9a5b04e3U, - 0xb267ed1940f1c61cU, 0xdf01e85f912e37a3U, 0x8b61313bbabce2c6U, - 0xae397d8aa96c1b77U, 0xd9c7dced53c72255U, 0x881cea14545c7575U, - 0xaa242499697392d2U, 0xd4ad2dbfc3d07787U, 0x84ec3c97da624ab4U, - 0xa6274bbdd0fadd61U, 0xcfb11ead453994baU, 0x81ceb32c4b43fcf4U, - 0xa2425ff75e14fc31U, 0xcad2f7f5359a3b3eU, 0xfd87b5f28300ca0dU, - 0x9e74d1b791e07e48U, 0xc612062576589ddaU, 0xf79687aed3eec551U, - 0x9abe14cd44753b52U, 0xc16d9a0095928a27U, 0xf1c90080baf72cb1U, - 0x971da05074da7beeU, 0xbce5086492111aeaU, 0xec1e4a7db69561a5U, - 0x9392ee8e921d5d07U, 0xb877aa3236a4b449U, 0xe69594bec44de15bU, - 0x901d7cf73ab0acd9U, 0xb424dc35095cd80fU, 0xe12e13424bb40e13U, - 0x8cbccc096f5088cbU, 0xafebff0bcb24aafeU, 0xdbe6fecebdedd5beU, - 0x89705f4136b4a597U, 0xabcc77118461cefcU, 0xd6bf94d5e57a42bcU, - 0x8637bd05af6c69b5U, 0xa7c5ac471b478423U, 0xd1b71758e219652bU, - 0x83126e978d4fdf3bU, 0xa3d70a3d70a3d70aU, 0xccccccccccccccccU, - 0x8000000000000000U, 0xa000000000000000U, 0xc800000000000000U, - 0xfa00000000000000U, 0x9c40000000000000U, 0xc350000000000000U, - 0xf424000000000000U, 0x9896800000000000U, 0xbebc200000000000U, - 0xee6b280000000000U, 0x9502f90000000000U, 0xba43b74000000000U, - 0xe8d4a51000000000U, 0x9184e72a00000000U, 0xb5e620f480000000U, - 0xe35fa931a0000000U, 0x8e1bc9bf04000000U, 0xb1a2bc2ec5000000U, - 0xde0b6b3a76400000U, 0x8ac7230489e80000U, 0xad78ebc5ac620000U, - 0xd8d726b7177a8000U, 0x878678326eac9000U, 0xa968163f0a57b400U, - 0xd3c21bcecceda100U, 0x84595161401484a0U, 0xa56fa5b99019a5c8U, - 0xcecb8f27f4200f3aU, 0x813f3978f8940984U, 0xa18f07d736b90be5U, - 0xc9f2c9cd04674edeU, 0xfc6f7c4045812296U, 0x9dc5ada82b70b59dU, - 0xc5371912364ce305U, 0xf684df56c3e01bc6U, 0x9a130b963a6c115cU, - 0xc097ce7bc90715b3U, 0xf0bdc21abb48db20U, 0x96769950b50d88f4U, - 0xbc143fa4e250eb31U, 0xeb194f8e1ae525fdU, 0x92efd1b8d0cf37beU, - 0xb7abc627050305adU, 0xe596b7b0c643c719U, 0x8f7e32ce7bea5c6fU, - 0xb35dbf821ae4f38bU, 0xe0352f62a19e306eU, 0x8c213d9da502de45U, - 0xaf298d050e4395d6U, 0xdaf3f04651d47b4cU, 0x88d8762bf324cd0fU, - 0xab0e93b6efee0053U, 0xd5d238a4abe98068U, 0x85a36366eb71f041U, - 0xa70c3c40a64e6c51U, 0xd0cf4b50cfe20765U, 0x82818f1281ed449fU, - 0xa321f2d7226895c7U, 0xcbea6f8ceb02bb39U, 0xfee50b7025c36a08U, - 0x9f4f2726179a2245U, 0xc722f0ef9d80aad6U, 0xf8ebad2b84e0d58bU, - 0x9b934c3b330c8577U, 0xc2781f49ffcfa6d5U, 0xf316271c7fc3908aU, - 0x97edd871cfda3a56U, 0xbde94e8e43d0c8ecU, 0xed63a231d4c4fb27U, - 0x945e455f24fb1cf8U, 0xb975d6b6ee39e436U, 0xe7d34c64a9c85d44U, - 0x90e40fbeea1d3a4aU, 0xb51d13aea4a488ddU, 0xe264589a4dcdab14U, - 0x8d7eb76070a08aecU, 0xb0de65388cc8ada8U, 0xdd15fe86affad912U, - 0x8a2dbf142dfcc7abU, 0xacb92ed9397bf996U, 0xd7e77a8f87daf7fbU, - 0x86f0ac99b4e8dafdU, 0xa8acd7c0222311bcU, 0xd2d80db02aabd62bU, - 0x83c7088e1aab65dbU, 0xa4b8cab1a1563f52U, 0xcde6fd5e09abcf26U, - 0x80b05e5ac60b6178U, 0xa0dc75f1778e39d6U, 0xc913936dd571c84cU, - 0xfb5878494ace3a5fU, 0x9d174b2dcec0e47bU, 0xc45d1df942711d9aU, - 0xf5746577930d6500U, 0x9968bf6abbe85f20U, 0xbfc2ef456ae276e8U, - 0xefb3ab16c59b14a2U, 0x95d04aee3b80ece5U, 0xbb445da9ca61281fU, - 0xea1575143cf97226U, 0x924d692ca61be758U, 0xb6e0c377cfa2e12eU, - 0xe498f455c38b997aU, 0x8edf98b59a373fecU, 0xb2977ee300c50fe7U, - 0xdf3d5e9bc0f653e1U, 0x8b865b215899f46cU, 0xae67f1e9aec07187U, - 0xda01ee641a708de9U, 0x884134fe908658b2U, 0xaa51823e34a7eedeU, - 0xd4e5e2cdc1d1ea96U, 0x850fadc09923329eU, 0xa6539930bf6bff45U, - 0xcfe87f7cef46ff16U, 0x81f14fae158c5f6eU, 0xa26da3999aef7749U, - 0xcb090c8001ab551cU, 0xfdcb4fa002162a63U, 0x9e9f11c4014dda7eU, - 0xc646d63501a1511dU, 0xf7d88bc24209a565U, 0x9ae757596946075fU, - 0xc1a12d2fc3978937U, 0xf209787bb47d6b84U, 0x9745eb4d50ce6332U, - 0xbd176620a501fbffU, 0xec5d3fa8ce427affU, 0x93ba47c980e98cdfU, - 0xb8a8d9bbe123f017U, 0xe6d3102ad96cec1dU, 0x9043ea1ac7e41392U, - 0xb454e4a179dd1877U, 0xe16a1dc9d8545e94U, 0x8ce2529e2734bb1dU, - 0xb01ae745b101e9e4U, 0xdc21a1171d42645dU, 0x899504ae72497ebaU, - 0xabfa45da0edbde69U, 0xd6f8d7509292d603U, 0x865b86925b9bc5c2U, - 0xa7f26836f282b732U, 0xd1ef0244af2364ffU, 0x8335616aed761f1fU, - 0xa402b9c5a8d3a6e7U, 0xcd036837130890a1U, 0x802221226be55a64U, - 0xa02aa96b06deb0fdU, 0xc83553c5c8965d3dU, 0xfa42a8b73abbf48cU, - 0x9c69a97284b578d7U, 0xc38413cf25e2d70dU, 0xf46518c2ef5b8cd1U, - 0x98bf2f79d5993802U, 0xbeeefb584aff8603U, 0xeeaaba2e5dbf6784U, - 0x952ab45cfa97a0b2U, 0xba756174393d88dfU, 0xe912b9d1478ceb17U, - 0x91abb422ccb812eeU, 0xb616a12b7fe617aaU, 0xe39c49765fdf9d94U, - 0x8e41ade9fbebc27dU, 0xb1d219647ae6b31cU, 0xde469fbd99a05fe3U, - 0x8aec23d680043beeU, 0xada72ccc20054ae9U, 0xd910f7ff28069da4U, - 0x87aa9aff79042286U, 0xa99541bf57452b28U, 0xd3fa922f2d1675f2U, - 0x847c9b5d7c2e09b7U, 0xa59bc234db398c25U, 0xcf02b2c21207ef2eU, - 0x8161afb94b44f57dU, 0xa1ba1ba79e1632dcU, 0xca28a291859bbf93U, - 0xfcb2cb35e702af78U, 0x9defbf01b061adabU, 0xc56baec21c7a1916U, - 0xf6c69a72a3989f5bU, 0x9a3c2087a63f6399U, 0xc0cb28a98fcf3c7fU, - 0xf0fdf2d3f3c30b9fU, 0x969eb7c47859e743U, 0xbc4665b596706114U, - 0xeb57ff22fc0c7959U, 0x9316ff75dd87cbd8U, 0xb7dcbf5354e9beceU, - 0xe5d3ef282a242e81U, 0x8fa475791a569d10U, 0xb38d92d760ec4455U, - 0xe070f78d3927556aU, 0x8c469ab843b89562U, 0xaf58416654a6babbU, - 0xdb2e51bfe9d0696aU, 0x88fcf317f22241e2U, 0xab3c2fddeeaad25aU, - 0xd60b3bd56a5586f1U, 0x85c7056562757456U, 0xa738c6bebb12d16cU, - 0xd106f86e69d785c7U, 0x82a45b450226b39cU, 0xa34d721642b06084U, - 0xcc20ce9bd35c78a5U, 0xff290242c83396ceU, 0x9f79a169bd203e41U, - 0xc75809c42c684dd1U, 0xf92e0c3537826145U, 0x9bbcc7a142b17ccbU, - 0xc2abf989935ddbfeU, 0xf356f7ebf83552feU, 0x98165af37b2153deU, - 0xbe1bf1b059e9a8d6U, 0xeda2ee1c7064130cU, 0x9485d4d1c63e8be7U, - 0xb9a74a0637ce2ee1U, 0xe8111c87c5c1ba99U, 0x910ab1d4db9914a0U, - 0xb54d5e4a127f59c8U, 0xe2a0b5dc971f303aU, 0x8da471a9de737e24U, - 0xb10d8e1456105dadU, 0xdd50f1996b947518U, 0x8a5296ffe33cc92fU, - 0xace73cbfdc0bfb7bU, 0xd8210befd30efa5aU, 0x8714a775e3e95c78U, - 0xa8d9d1535ce3b396U, 0xd31045a8341ca07cU, 0x83ea2b892091e44dU, - 0xa4e4b66b68b65d60U, 0xce1de40642e3f4b9U, 0x80d2ae83e9ce78f3U, - 0xa1075a24e4421730U, 0xc94930ae1d529cfcU, 0xfb9b7cd9a4a7443cU, - 0x9d412e0806e88aa5U, 0xc491798a08a2ad4eU, 0xf5b5d7ec8acb58a2U, - 0x9991a6f3d6bf1765U, 0xbff610b0cc6edd3fU, 0xeff394dcff8a948eU, - 0x95f83d0a1fb69cd9U, 0xbb764c4ca7a4440fU, 0xea53df5fd18d5513U, - 0x92746b9be2f8552cU, 0xb7118682dbb66a77U, 0xe4d5e82392a40515U, - 0x8f05b1163ba6832dU, 0xb2c71d5bca9023f8U, 0xdf78e4b2bd342cf6U, - 0x8bab8eefb6409c1aU, 0xae9672aba3d0c320U, 0xda3c0f568cc4f3e8U, - 0x8865899617fb1871U, 0xaa7eebfb9df9de8dU, 0xd51ea6fa85785631U, - 0x8533285c936b35deU, 0xa67ff273b8460356U, 0xd01fef10a657842cU, - 0x8213f56a67f6b29bU, 0xa298f2c501f45f42U, 0xcb3f2f7642717713U, - 0xfe0efb53d30dd4d7U, 0x9ec95d1463e8a506U, 0xc67bb4597ce2ce48U, - 0xf81aa16fdc1b81daU, 0x9b10a4e5e9913128U, 0xc1d4ce1f63f57d72U, - 0xf24a01a73cf2dccfU, 0x976e41088617ca01U, 0xbd49d14aa79dbc82U, - 0xec9c459d51852ba2U, 0x93e1ab8252f33b45U, 0xb8da1662e7b00a17U, - 0xe7109bfba19c0c9dU, 0x906a617d450187e2U, 0xb484f9dc9641e9daU, - 0xe1a63853bbd26451U, 0x8d07e33455637eb2U, 0xb049dc016abc5e5fU, - 0xdc5c5301c56b75f7U, 0x89b9b3e11b6329baU, 0xac2820d9623bf429U, - 0xd732290fbacaf133U, 0x867f59a9d4bed6c0U, 0xa81f301449ee8c70U, - 0xd226fc195c6a2f8cU, 0x83585d8fd9c25db7U, 0xa42e74f3d032f525U, - 0xcd3a1230c43fb26fU, 0x80444b5e7aa7cf85U, 0xa0555e361951c366U, - 0xc86ab5c39fa63440U, 0xfa856334878fc150U, 0x9c935e00d4b9d8d2U, - 0xc3b8358109e84f07U, 0xf4a642e14c6262c8U, 0x98e7e9cccfbd7dbdU, - 0xbf21e44003acdd2cU, 0xeeea5d5004981478U, 0x95527a5202df0ccbU, - 0xbaa718e68396cffdU, 0xe950df20247c83fdU, 0x91d28b7416cdd27eU, - 0xb6472e511c81471dU, 0xe3d8f9e563a198e5U, 0x8e679c2f5e44ff8fU, -}; - -const int16_t kPower10ExponentTable[] = { - -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, -1170, -1166, - -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, -1136, -1133, -1130, - -1127, -1123, -1120, -1117, -1113, -1110, -1107, -1103, -1100, -1097, -1093, - -1090, -1087, -1083, -1080, -1077, -1073, -1070, -1067, -1063, -1060, -1057, - -1053, -1050, -1047, -1043, -1040, -1037, -1034, -1030, -1027, -1024, -1020, - -1017, -1014, -1010, -1007, -1004, -1000, -997, -994, -990, -987, -984, - -980, -977, -974, -970, -967, -964, -960, -957, -954, -950, -947, - -944, -940, -937, -934, -931, -927, -924, -921, -917, -914, -911, - -907, -904, -901, -897, -894, -891, -887, -884, -881, -877, -874, - -871, -867, -864, -861, -857, -854, -851, -847, -844, -841, -838, - -834, -831, -828, -824, -821, -818, -814, -811, -808, -804, -801, - -798, -794, -791, -788, -784, -781, -778, -774, -771, -768, -764, - -761, -758, -754, -751, -748, -744, -741, -738, -735, -731, -728, - -725, -721, -718, -715, -711, -708, -705, -701, -698, -695, -691, - -688, -685, -681, -678, -675, -671, -668, -665, -661, -658, -655, - -651, -648, -645, -642, -638, -635, -632, -628, -625, -622, -618, - -615, -612, -608, -605, -602, -598, -595, -592, -588, -585, -582, - -578, -575, -572, -568, -565, -562, -558, -555, -552, -549, -545, - -542, -539, -535, -532, -529, -525, -522, -519, -515, -512, -509, - -505, -502, -499, -495, -492, -489, -485, -482, -479, -475, -472, - -469, -465, -462, -459, -455, -452, -449, -446, -442, -439, -436, - -432, -429, -426, -422, -419, -416, -412, -409, -406, -402, -399, - -396, -392, -389, -386, -382, -379, -376, -372, -369, -366, -362, - -359, -356, -353, -349, -346, -343, -339, -336, -333, -329, -326, - -323, -319, -316, -313, -309, -306, -303, -299, -296, -293, -289, - -286, -283, -279, -276, -273, -269, -266, -263, -259, -256, -253, - -250, -246, -243, -240, -236, -233, -230, -226, -223, -220, -216, - -213, -210, -206, -203, -200, -196, -193, -190, -186, -183, -180, - -176, -173, -170, -166, -163, -160, -157, -153, -150, -147, -143, - -140, -137, -133, -130, -127, -123, -120, -117, -113, -110, -107, - -103, -100, -97, -93, -90, -87, -83, -80, -77, -73, -70, - -67, -63, -60, -57, -54, -50, -47, -44, -40, -37, -34, - -30, -27, -24, -20, -17, -14, -10, -7, -4, 0, 3, - 6, 10, 13, 16, 20, 23, 26, 30, 33, 36, 39, - 43, 46, 49, 53, 56, 59, 63, 66, 69, 73, 76, - 79, 83, 86, 89, 93, 96, 99, 103, 106, 109, 113, - 116, 119, 123, 126, 129, 132, 136, 139, 142, 146, 149, - 152, 156, 159, 162, 166, 169, 172, 176, 179, 182, 186, - 189, 192, 196, 199, 202, 206, 209, 212, 216, 219, 222, - 226, 229, 232, 235, 239, 242, 245, 249, 252, 255, 259, - 262, 265, 269, 272, 275, 279, 282, 285, 289, 292, 295, - 299, 302, 305, 309, 312, 315, 319, 322, 325, 328, 332, - 335, 338, 342, 345, 348, 352, 355, 358, 362, 365, 368, - 372, 375, 378, 382, 385, 388, 392, 395, 398, 402, 405, - 408, 412, 415, 418, 422, 425, 428, 431, 435, 438, 441, - 445, 448, 451, 455, 458, 461, 465, 468, 471, 475, 478, - 481, 485, 488, 491, 495, 498, 501, 505, 508, 511, 515, - 518, 521, 524, 528, 531, 534, 538, 541, 544, 548, 551, - 554, 558, 561, 564, 568, 571, 574, 578, 581, 584, 588, - 591, 594, 598, 601, 604, 608, 611, 614, 617, 621, 624, - 627, 631, 634, 637, 641, 644, 647, 651, 654, 657, 661, - 664, 667, 671, 674, 677, 681, 684, 687, 691, 694, 697, - 701, 704, 707, 711, 714, 717, 720, 724, 727, 730, 734, - 737, 740, 744, 747, 750, 754, 757, 760, 764, 767, 770, - 774, 777, 780, 784, 787, 790, 794, 797, 800, 804, 807, - 810, 813, 817, 820, 823, 827, 830, 833, 837, 840, 843, - 847, 850, 853, 857, 860, 863, 867, 870, 873, 877, 880, - 883, 887, 890, 893, 897, 900, 903, 907, 910, 913, 916, - 920, 923, 926, 930, 933, 936, 940, 943, 946, 950, 953, - 956, 960, -}; - -} // namespace + if (fmt_flags == chars_format::scientific) { + result.ec = std::errc::invalid_argument; + } else { + result.ptr = first + 1; + value = negative ? -0.0 : 0.0; + } + return result; + } + // We matched a value. + result.ptr = hex_parse.end; + if (HandleEdgeCase(hex_parse, negative, &value)) { + return result; + } + CalculatedFloat calculated = + CalculateFromParsedHexadecimal<FloatType>(hex_parse); + EncodeResult(calculated, negative, &result, &value); + return result; + } + // Otherwise, we choose the number base based on the flags. + if ((fmt_flags & chars_format::hex) == chars_format::hex) { + strings_internal::ParsedFloat hex_parse = + strings_internal::ParseFloat<16>(first, last, fmt_flags); + if (hex_parse.end == nullptr) { + result.ec = std::errc::invalid_argument; + return result; + } + result.ptr = hex_parse.end; + if (HandleEdgeCase(hex_parse, negative, &value)) { + return result; + } + CalculatedFloat calculated = + CalculateFromParsedHexadecimal<FloatType>(hex_parse); + EncodeResult(calculated, negative, &result, &value); + return result; + } else { + strings_internal::ParsedFloat decimal_parse = + strings_internal::ParseFloat<10>(first, last, fmt_flags); + if (decimal_parse.end == nullptr) { + result.ec = std::errc::invalid_argument; + return result; + } + result.ptr = decimal_parse.end; + if (HandleEdgeCase(decimal_parse, negative, &value)) { + return result; + } + CalculatedFloat calculated = + CalculateFromParsedDecimal<FloatType>(decimal_parse); + EncodeResult(calculated, negative, &result, &value); + return result; + } +} +} // namespace + +from_chars_result from_chars(const char* first, const char* last, double& value, + chars_format fmt) { + return FromCharsImpl(first, last, value, fmt); +} + +from_chars_result from_chars(const char* first, const char* last, float& value, + chars_format fmt) { + return FromCharsImpl(first, last, value, fmt); +} + +namespace { + +// Table of powers of 10, from kPower10TableMin to kPower10TableMax. +// +// kPower10MantissaTable[i - kPower10TableMin] stores the 64-bit mantissa (high +// bit always on), and kPower10ExponentTable[i - kPower10TableMin] stores the +// power-of-two exponent. For a given number i, this gives the unique mantissa +// and exponent such that mantissa * 2**exponent <= 10**i < (mantissa + 1) * +// 2**exponent. + +const uint64_t kPower10MantissaTable[] = { + 0xeef453d6923bd65aU, 0x9558b4661b6565f8U, 0xbaaee17fa23ebf76U, + 0xe95a99df8ace6f53U, 0x91d8a02bb6c10594U, 0xb64ec836a47146f9U, + 0xe3e27a444d8d98b7U, 0x8e6d8c6ab0787f72U, 0xb208ef855c969f4fU, + 0xde8b2b66b3bc4723U, 0x8b16fb203055ac76U, 0xaddcb9e83c6b1793U, + 0xd953e8624b85dd78U, 0x87d4713d6f33aa6bU, 0xa9c98d8ccb009506U, + 0xd43bf0effdc0ba48U, 0x84a57695fe98746dU, 0xa5ced43b7e3e9188U, + 0xcf42894a5dce35eaU, 0x818995ce7aa0e1b2U, 0xa1ebfb4219491a1fU, + 0xca66fa129f9b60a6U, 0xfd00b897478238d0U, 0x9e20735e8cb16382U, + 0xc5a890362fddbc62U, 0xf712b443bbd52b7bU, 0x9a6bb0aa55653b2dU, + 0xc1069cd4eabe89f8U, 0xf148440a256e2c76U, 0x96cd2a865764dbcaU, + 0xbc807527ed3e12bcU, 0xeba09271e88d976bU, 0x93445b8731587ea3U, + 0xb8157268fdae9e4cU, 0xe61acf033d1a45dfU, 0x8fd0c16206306babU, + 0xb3c4f1ba87bc8696U, 0xe0b62e2929aba83cU, 0x8c71dcd9ba0b4925U, + 0xaf8e5410288e1b6fU, 0xdb71e91432b1a24aU, 0x892731ac9faf056eU, + 0xab70fe17c79ac6caU, 0xd64d3d9db981787dU, 0x85f0468293f0eb4eU, + 0xa76c582338ed2621U, 0xd1476e2c07286faaU, 0x82cca4db847945caU, + 0xa37fce126597973cU, 0xcc5fc196fefd7d0cU, 0xff77b1fcbebcdc4fU, + 0x9faacf3df73609b1U, 0xc795830d75038c1dU, 0xf97ae3d0d2446f25U, + 0x9becce62836ac577U, 0xc2e801fb244576d5U, 0xf3a20279ed56d48aU, + 0x9845418c345644d6U, 0xbe5691ef416bd60cU, 0xedec366b11c6cb8fU, + 0x94b3a202eb1c3f39U, 0xb9e08a83a5e34f07U, 0xe858ad248f5c22c9U, + 0x91376c36d99995beU, 0xb58547448ffffb2dU, 0xe2e69915b3fff9f9U, + 0x8dd01fad907ffc3bU, 0xb1442798f49ffb4aU, 0xdd95317f31c7fa1dU, + 0x8a7d3eef7f1cfc52U, 0xad1c8eab5ee43b66U, 0xd863b256369d4a40U, + 0x873e4f75e2224e68U, 0xa90de3535aaae202U, 0xd3515c2831559a83U, + 0x8412d9991ed58091U, 0xa5178fff668ae0b6U, 0xce5d73ff402d98e3U, + 0x80fa687f881c7f8eU, 0xa139029f6a239f72U, 0xc987434744ac874eU, + 0xfbe9141915d7a922U, 0x9d71ac8fada6c9b5U, 0xc4ce17b399107c22U, + 0xf6019da07f549b2bU, 0x99c102844f94e0fbU, 0xc0314325637a1939U, + 0xf03d93eebc589f88U, 0x96267c7535b763b5U, 0xbbb01b9283253ca2U, + 0xea9c227723ee8bcbU, 0x92a1958a7675175fU, 0xb749faed14125d36U, + 0xe51c79a85916f484U, 0x8f31cc0937ae58d2U, 0xb2fe3f0b8599ef07U, + 0xdfbdcece67006ac9U, 0x8bd6a141006042bdU, 0xaecc49914078536dU, + 0xda7f5bf590966848U, 0x888f99797a5e012dU, 0xaab37fd7d8f58178U, + 0xd5605fcdcf32e1d6U, 0x855c3be0a17fcd26U, 0xa6b34ad8c9dfc06fU, + 0xd0601d8efc57b08bU, 0x823c12795db6ce57U, 0xa2cb1717b52481edU, + 0xcb7ddcdda26da268U, 0xfe5d54150b090b02U, 0x9efa548d26e5a6e1U, + 0xc6b8e9b0709f109aU, 0xf867241c8cc6d4c0U, 0x9b407691d7fc44f8U, + 0xc21094364dfb5636U, 0xf294b943e17a2bc4U, 0x979cf3ca6cec5b5aU, + 0xbd8430bd08277231U, 0xece53cec4a314ebdU, 0x940f4613ae5ed136U, + 0xb913179899f68584U, 0xe757dd7ec07426e5U, 0x9096ea6f3848984fU, + 0xb4bca50b065abe63U, 0xe1ebce4dc7f16dfbU, 0x8d3360f09cf6e4bdU, + 0xb080392cc4349decU, 0xdca04777f541c567U, 0x89e42caaf9491b60U, + 0xac5d37d5b79b6239U, 0xd77485cb25823ac7U, 0x86a8d39ef77164bcU, + 0xa8530886b54dbdebU, 0xd267caa862a12d66U, 0x8380dea93da4bc60U, + 0xa46116538d0deb78U, 0xcd795be870516656U, 0x806bd9714632dff6U, + 0xa086cfcd97bf97f3U, 0xc8a883c0fdaf7df0U, 0xfad2a4b13d1b5d6cU, + 0x9cc3a6eec6311a63U, 0xc3f490aa77bd60fcU, 0xf4f1b4d515acb93bU, + 0x991711052d8bf3c5U, 0xbf5cd54678eef0b6U, 0xef340a98172aace4U, + 0x9580869f0e7aac0eU, 0xbae0a846d2195712U, 0xe998d258869facd7U, + 0x91ff83775423cc06U, 0xb67f6455292cbf08U, 0xe41f3d6a7377eecaU, + 0x8e938662882af53eU, 0xb23867fb2a35b28dU, 0xdec681f9f4c31f31U, + 0x8b3c113c38f9f37eU, 0xae0b158b4738705eU, 0xd98ddaee19068c76U, + 0x87f8a8d4cfa417c9U, 0xa9f6d30a038d1dbcU, 0xd47487cc8470652bU, + 0x84c8d4dfd2c63f3bU, 0xa5fb0a17c777cf09U, 0xcf79cc9db955c2ccU, + 0x81ac1fe293d599bfU, 0xa21727db38cb002fU, 0xca9cf1d206fdc03bU, + 0xfd442e4688bd304aU, 0x9e4a9cec15763e2eU, 0xc5dd44271ad3cdbaU, + 0xf7549530e188c128U, 0x9a94dd3e8cf578b9U, 0xc13a148e3032d6e7U, + 0xf18899b1bc3f8ca1U, 0x96f5600f15a7b7e5U, 0xbcb2b812db11a5deU, + 0xebdf661791d60f56U, 0x936b9fcebb25c995U, 0xb84687c269ef3bfbU, + 0xe65829b3046b0afaU, 0x8ff71a0fe2c2e6dcU, 0xb3f4e093db73a093U, + 0xe0f218b8d25088b8U, 0x8c974f7383725573U, 0xafbd2350644eeacfU, + 0xdbac6c247d62a583U, 0x894bc396ce5da772U, 0xab9eb47c81f5114fU, + 0xd686619ba27255a2U, 0x8613fd0145877585U, 0xa798fc4196e952e7U, + 0xd17f3b51fca3a7a0U, 0x82ef85133de648c4U, 0xa3ab66580d5fdaf5U, + 0xcc963fee10b7d1b3U, 0xffbbcfe994e5c61fU, 0x9fd561f1fd0f9bd3U, + 0xc7caba6e7c5382c8U, 0xf9bd690a1b68637bU, 0x9c1661a651213e2dU, + 0xc31bfa0fe5698db8U, 0xf3e2f893dec3f126U, 0x986ddb5c6b3a76b7U, + 0xbe89523386091465U, 0xee2ba6c0678b597fU, 0x94db483840b717efU, + 0xba121a4650e4ddebU, 0xe896a0d7e51e1566U, 0x915e2486ef32cd60U, + 0xb5b5ada8aaff80b8U, 0xe3231912d5bf60e6U, 0x8df5efabc5979c8fU, + 0xb1736b96b6fd83b3U, 0xddd0467c64bce4a0U, 0x8aa22c0dbef60ee4U, + 0xad4ab7112eb3929dU, 0xd89d64d57a607744U, 0x87625f056c7c4a8bU, + 0xa93af6c6c79b5d2dU, 0xd389b47879823479U, 0x843610cb4bf160cbU, + 0xa54394fe1eedb8feU, 0xce947a3da6a9273eU, 0x811ccc668829b887U, + 0xa163ff802a3426a8U, 0xc9bcff6034c13052U, 0xfc2c3f3841f17c67U, + 0x9d9ba7832936edc0U, 0xc5029163f384a931U, 0xf64335bcf065d37dU, + 0x99ea0196163fa42eU, 0xc06481fb9bcf8d39U, 0xf07da27a82c37088U, + 0x964e858c91ba2655U, 0xbbe226efb628afeaU, 0xeadab0aba3b2dbe5U, + 0x92c8ae6b464fc96fU, 0xb77ada0617e3bbcbU, 0xe55990879ddcaabdU, + 0x8f57fa54c2a9eab6U, 0xb32df8e9f3546564U, 0xdff9772470297ebdU, + 0x8bfbea76c619ef36U, 0xaefae51477a06b03U, 0xdab99e59958885c4U, + 0x88b402f7fd75539bU, 0xaae103b5fcd2a881U, 0xd59944a37c0752a2U, + 0x857fcae62d8493a5U, 0xa6dfbd9fb8e5b88eU, 0xd097ad07a71f26b2U, + 0x825ecc24c873782fU, 0xa2f67f2dfa90563bU, 0xcbb41ef979346bcaU, + 0xfea126b7d78186bcU, 0x9f24b832e6b0f436U, 0xc6ede63fa05d3143U, + 0xf8a95fcf88747d94U, 0x9b69dbe1b548ce7cU, 0xc24452da229b021bU, + 0xf2d56790ab41c2a2U, 0x97c560ba6b0919a5U, 0xbdb6b8e905cb600fU, + 0xed246723473e3813U, 0x9436c0760c86e30bU, 0xb94470938fa89bceU, + 0xe7958cb87392c2c2U, 0x90bd77f3483bb9b9U, 0xb4ecd5f01a4aa828U, + 0xe2280b6c20dd5232U, 0x8d590723948a535fU, 0xb0af48ec79ace837U, + 0xdcdb1b2798182244U, 0x8a08f0f8bf0f156bU, 0xac8b2d36eed2dac5U, + 0xd7adf884aa879177U, 0x86ccbb52ea94baeaU, 0xa87fea27a539e9a5U, + 0xd29fe4b18e88640eU, 0x83a3eeeef9153e89U, 0xa48ceaaab75a8e2bU, + 0xcdb02555653131b6U, 0x808e17555f3ebf11U, 0xa0b19d2ab70e6ed6U, + 0xc8de047564d20a8bU, 0xfb158592be068d2eU, 0x9ced737bb6c4183dU, + 0xc428d05aa4751e4cU, 0xf53304714d9265dfU, 0x993fe2c6d07b7fabU, + 0xbf8fdb78849a5f96U, 0xef73d256a5c0f77cU, 0x95a8637627989aadU, + 0xbb127c53b17ec159U, 0xe9d71b689dde71afU, 0x9226712162ab070dU, + 0xb6b00d69bb55c8d1U, 0xe45c10c42a2b3b05U, 0x8eb98a7a9a5b04e3U, + 0xb267ed1940f1c61cU, 0xdf01e85f912e37a3U, 0x8b61313bbabce2c6U, + 0xae397d8aa96c1b77U, 0xd9c7dced53c72255U, 0x881cea14545c7575U, + 0xaa242499697392d2U, 0xd4ad2dbfc3d07787U, 0x84ec3c97da624ab4U, + 0xa6274bbdd0fadd61U, 0xcfb11ead453994baU, 0x81ceb32c4b43fcf4U, + 0xa2425ff75e14fc31U, 0xcad2f7f5359a3b3eU, 0xfd87b5f28300ca0dU, + 0x9e74d1b791e07e48U, 0xc612062576589ddaU, 0xf79687aed3eec551U, + 0x9abe14cd44753b52U, 0xc16d9a0095928a27U, 0xf1c90080baf72cb1U, + 0x971da05074da7beeU, 0xbce5086492111aeaU, 0xec1e4a7db69561a5U, + 0x9392ee8e921d5d07U, 0xb877aa3236a4b449U, 0xe69594bec44de15bU, + 0x901d7cf73ab0acd9U, 0xb424dc35095cd80fU, 0xe12e13424bb40e13U, + 0x8cbccc096f5088cbU, 0xafebff0bcb24aafeU, 0xdbe6fecebdedd5beU, + 0x89705f4136b4a597U, 0xabcc77118461cefcU, 0xd6bf94d5e57a42bcU, + 0x8637bd05af6c69b5U, 0xa7c5ac471b478423U, 0xd1b71758e219652bU, + 0x83126e978d4fdf3bU, 0xa3d70a3d70a3d70aU, 0xccccccccccccccccU, + 0x8000000000000000U, 0xa000000000000000U, 0xc800000000000000U, + 0xfa00000000000000U, 0x9c40000000000000U, 0xc350000000000000U, + 0xf424000000000000U, 0x9896800000000000U, 0xbebc200000000000U, + 0xee6b280000000000U, 0x9502f90000000000U, 0xba43b74000000000U, + 0xe8d4a51000000000U, 0x9184e72a00000000U, 0xb5e620f480000000U, + 0xe35fa931a0000000U, 0x8e1bc9bf04000000U, 0xb1a2bc2ec5000000U, + 0xde0b6b3a76400000U, 0x8ac7230489e80000U, 0xad78ebc5ac620000U, + 0xd8d726b7177a8000U, 0x878678326eac9000U, 0xa968163f0a57b400U, + 0xd3c21bcecceda100U, 0x84595161401484a0U, 0xa56fa5b99019a5c8U, + 0xcecb8f27f4200f3aU, 0x813f3978f8940984U, 0xa18f07d736b90be5U, + 0xc9f2c9cd04674edeU, 0xfc6f7c4045812296U, 0x9dc5ada82b70b59dU, + 0xc5371912364ce305U, 0xf684df56c3e01bc6U, 0x9a130b963a6c115cU, + 0xc097ce7bc90715b3U, 0xf0bdc21abb48db20U, 0x96769950b50d88f4U, + 0xbc143fa4e250eb31U, 0xeb194f8e1ae525fdU, 0x92efd1b8d0cf37beU, + 0xb7abc627050305adU, 0xe596b7b0c643c719U, 0x8f7e32ce7bea5c6fU, + 0xb35dbf821ae4f38bU, 0xe0352f62a19e306eU, 0x8c213d9da502de45U, + 0xaf298d050e4395d6U, 0xdaf3f04651d47b4cU, 0x88d8762bf324cd0fU, + 0xab0e93b6efee0053U, 0xd5d238a4abe98068U, 0x85a36366eb71f041U, + 0xa70c3c40a64e6c51U, 0xd0cf4b50cfe20765U, 0x82818f1281ed449fU, + 0xa321f2d7226895c7U, 0xcbea6f8ceb02bb39U, 0xfee50b7025c36a08U, + 0x9f4f2726179a2245U, 0xc722f0ef9d80aad6U, 0xf8ebad2b84e0d58bU, + 0x9b934c3b330c8577U, 0xc2781f49ffcfa6d5U, 0xf316271c7fc3908aU, + 0x97edd871cfda3a56U, 0xbde94e8e43d0c8ecU, 0xed63a231d4c4fb27U, + 0x945e455f24fb1cf8U, 0xb975d6b6ee39e436U, 0xe7d34c64a9c85d44U, + 0x90e40fbeea1d3a4aU, 0xb51d13aea4a488ddU, 0xe264589a4dcdab14U, + 0x8d7eb76070a08aecU, 0xb0de65388cc8ada8U, 0xdd15fe86affad912U, + 0x8a2dbf142dfcc7abU, 0xacb92ed9397bf996U, 0xd7e77a8f87daf7fbU, + 0x86f0ac99b4e8dafdU, 0xa8acd7c0222311bcU, 0xd2d80db02aabd62bU, + 0x83c7088e1aab65dbU, 0xa4b8cab1a1563f52U, 0xcde6fd5e09abcf26U, + 0x80b05e5ac60b6178U, 0xa0dc75f1778e39d6U, 0xc913936dd571c84cU, + 0xfb5878494ace3a5fU, 0x9d174b2dcec0e47bU, 0xc45d1df942711d9aU, + 0xf5746577930d6500U, 0x9968bf6abbe85f20U, 0xbfc2ef456ae276e8U, + 0xefb3ab16c59b14a2U, 0x95d04aee3b80ece5U, 0xbb445da9ca61281fU, + 0xea1575143cf97226U, 0x924d692ca61be758U, 0xb6e0c377cfa2e12eU, + 0xe498f455c38b997aU, 0x8edf98b59a373fecU, 0xb2977ee300c50fe7U, + 0xdf3d5e9bc0f653e1U, 0x8b865b215899f46cU, 0xae67f1e9aec07187U, + 0xda01ee641a708de9U, 0x884134fe908658b2U, 0xaa51823e34a7eedeU, + 0xd4e5e2cdc1d1ea96U, 0x850fadc09923329eU, 0xa6539930bf6bff45U, + 0xcfe87f7cef46ff16U, 0x81f14fae158c5f6eU, 0xa26da3999aef7749U, + 0xcb090c8001ab551cU, 0xfdcb4fa002162a63U, 0x9e9f11c4014dda7eU, + 0xc646d63501a1511dU, 0xf7d88bc24209a565U, 0x9ae757596946075fU, + 0xc1a12d2fc3978937U, 0xf209787bb47d6b84U, 0x9745eb4d50ce6332U, + 0xbd176620a501fbffU, 0xec5d3fa8ce427affU, 0x93ba47c980e98cdfU, + 0xb8a8d9bbe123f017U, 0xe6d3102ad96cec1dU, 0x9043ea1ac7e41392U, + 0xb454e4a179dd1877U, 0xe16a1dc9d8545e94U, 0x8ce2529e2734bb1dU, + 0xb01ae745b101e9e4U, 0xdc21a1171d42645dU, 0x899504ae72497ebaU, + 0xabfa45da0edbde69U, 0xd6f8d7509292d603U, 0x865b86925b9bc5c2U, + 0xa7f26836f282b732U, 0xd1ef0244af2364ffU, 0x8335616aed761f1fU, + 0xa402b9c5a8d3a6e7U, 0xcd036837130890a1U, 0x802221226be55a64U, + 0xa02aa96b06deb0fdU, 0xc83553c5c8965d3dU, 0xfa42a8b73abbf48cU, + 0x9c69a97284b578d7U, 0xc38413cf25e2d70dU, 0xf46518c2ef5b8cd1U, + 0x98bf2f79d5993802U, 0xbeeefb584aff8603U, 0xeeaaba2e5dbf6784U, + 0x952ab45cfa97a0b2U, 0xba756174393d88dfU, 0xe912b9d1478ceb17U, + 0x91abb422ccb812eeU, 0xb616a12b7fe617aaU, 0xe39c49765fdf9d94U, + 0x8e41ade9fbebc27dU, 0xb1d219647ae6b31cU, 0xde469fbd99a05fe3U, + 0x8aec23d680043beeU, 0xada72ccc20054ae9U, 0xd910f7ff28069da4U, + 0x87aa9aff79042286U, 0xa99541bf57452b28U, 0xd3fa922f2d1675f2U, + 0x847c9b5d7c2e09b7U, 0xa59bc234db398c25U, 0xcf02b2c21207ef2eU, + 0x8161afb94b44f57dU, 0xa1ba1ba79e1632dcU, 0xca28a291859bbf93U, + 0xfcb2cb35e702af78U, 0x9defbf01b061adabU, 0xc56baec21c7a1916U, + 0xf6c69a72a3989f5bU, 0x9a3c2087a63f6399U, 0xc0cb28a98fcf3c7fU, + 0xf0fdf2d3f3c30b9fU, 0x969eb7c47859e743U, 0xbc4665b596706114U, + 0xeb57ff22fc0c7959U, 0x9316ff75dd87cbd8U, 0xb7dcbf5354e9beceU, + 0xe5d3ef282a242e81U, 0x8fa475791a569d10U, 0xb38d92d760ec4455U, + 0xe070f78d3927556aU, 0x8c469ab843b89562U, 0xaf58416654a6babbU, + 0xdb2e51bfe9d0696aU, 0x88fcf317f22241e2U, 0xab3c2fddeeaad25aU, + 0xd60b3bd56a5586f1U, 0x85c7056562757456U, 0xa738c6bebb12d16cU, + 0xd106f86e69d785c7U, 0x82a45b450226b39cU, 0xa34d721642b06084U, + 0xcc20ce9bd35c78a5U, 0xff290242c83396ceU, 0x9f79a169bd203e41U, + 0xc75809c42c684dd1U, 0xf92e0c3537826145U, 0x9bbcc7a142b17ccbU, + 0xc2abf989935ddbfeU, 0xf356f7ebf83552feU, 0x98165af37b2153deU, + 0xbe1bf1b059e9a8d6U, 0xeda2ee1c7064130cU, 0x9485d4d1c63e8be7U, + 0xb9a74a0637ce2ee1U, 0xe8111c87c5c1ba99U, 0x910ab1d4db9914a0U, + 0xb54d5e4a127f59c8U, 0xe2a0b5dc971f303aU, 0x8da471a9de737e24U, + 0xb10d8e1456105dadU, 0xdd50f1996b947518U, 0x8a5296ffe33cc92fU, + 0xace73cbfdc0bfb7bU, 0xd8210befd30efa5aU, 0x8714a775e3e95c78U, + 0xa8d9d1535ce3b396U, 0xd31045a8341ca07cU, 0x83ea2b892091e44dU, + 0xa4e4b66b68b65d60U, 0xce1de40642e3f4b9U, 0x80d2ae83e9ce78f3U, + 0xa1075a24e4421730U, 0xc94930ae1d529cfcU, 0xfb9b7cd9a4a7443cU, + 0x9d412e0806e88aa5U, 0xc491798a08a2ad4eU, 0xf5b5d7ec8acb58a2U, + 0x9991a6f3d6bf1765U, 0xbff610b0cc6edd3fU, 0xeff394dcff8a948eU, + 0x95f83d0a1fb69cd9U, 0xbb764c4ca7a4440fU, 0xea53df5fd18d5513U, + 0x92746b9be2f8552cU, 0xb7118682dbb66a77U, 0xe4d5e82392a40515U, + 0x8f05b1163ba6832dU, 0xb2c71d5bca9023f8U, 0xdf78e4b2bd342cf6U, + 0x8bab8eefb6409c1aU, 0xae9672aba3d0c320U, 0xda3c0f568cc4f3e8U, + 0x8865899617fb1871U, 0xaa7eebfb9df9de8dU, 0xd51ea6fa85785631U, + 0x8533285c936b35deU, 0xa67ff273b8460356U, 0xd01fef10a657842cU, + 0x8213f56a67f6b29bU, 0xa298f2c501f45f42U, 0xcb3f2f7642717713U, + 0xfe0efb53d30dd4d7U, 0x9ec95d1463e8a506U, 0xc67bb4597ce2ce48U, + 0xf81aa16fdc1b81daU, 0x9b10a4e5e9913128U, 0xc1d4ce1f63f57d72U, + 0xf24a01a73cf2dccfU, 0x976e41088617ca01U, 0xbd49d14aa79dbc82U, + 0xec9c459d51852ba2U, 0x93e1ab8252f33b45U, 0xb8da1662e7b00a17U, + 0xe7109bfba19c0c9dU, 0x906a617d450187e2U, 0xb484f9dc9641e9daU, + 0xe1a63853bbd26451U, 0x8d07e33455637eb2U, 0xb049dc016abc5e5fU, + 0xdc5c5301c56b75f7U, 0x89b9b3e11b6329baU, 0xac2820d9623bf429U, + 0xd732290fbacaf133U, 0x867f59a9d4bed6c0U, 0xa81f301449ee8c70U, + 0xd226fc195c6a2f8cU, 0x83585d8fd9c25db7U, 0xa42e74f3d032f525U, + 0xcd3a1230c43fb26fU, 0x80444b5e7aa7cf85U, 0xa0555e361951c366U, + 0xc86ab5c39fa63440U, 0xfa856334878fc150U, 0x9c935e00d4b9d8d2U, + 0xc3b8358109e84f07U, 0xf4a642e14c6262c8U, 0x98e7e9cccfbd7dbdU, + 0xbf21e44003acdd2cU, 0xeeea5d5004981478U, 0x95527a5202df0ccbU, + 0xbaa718e68396cffdU, 0xe950df20247c83fdU, 0x91d28b7416cdd27eU, + 0xb6472e511c81471dU, 0xe3d8f9e563a198e5U, 0x8e679c2f5e44ff8fU, +}; + +const int16_t kPower10ExponentTable[] = { + -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, -1170, -1166, + -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, -1136, -1133, -1130, + -1127, -1123, -1120, -1117, -1113, -1110, -1107, -1103, -1100, -1097, -1093, + -1090, -1087, -1083, -1080, -1077, -1073, -1070, -1067, -1063, -1060, -1057, + -1053, -1050, -1047, -1043, -1040, -1037, -1034, -1030, -1027, -1024, -1020, + -1017, -1014, -1010, -1007, -1004, -1000, -997, -994, -990, -987, -984, + -980, -977, -974, -970, -967, -964, -960, -957, -954, -950, -947, + -944, -940, -937, -934, -931, -927, -924, -921, -917, -914, -911, + -907, -904, -901, -897, -894, -891, -887, -884, -881, -877, -874, + -871, -867, -864, -861, -857, -854, -851, -847, -844, -841, -838, + -834, -831, -828, -824, -821, -818, -814, -811, -808, -804, -801, + -798, -794, -791, -788, -784, -781, -778, -774, -771, -768, -764, + -761, -758, -754, -751, -748, -744, -741, -738, -735, -731, -728, + -725, -721, -718, -715, -711, -708, -705, -701, -698, -695, -691, + -688, -685, -681, -678, -675, -671, -668, -665, -661, -658, -655, + -651, -648, -645, -642, -638, -635, -632, -628, -625, -622, -618, + -615, -612, -608, -605, -602, -598, -595, -592, -588, -585, -582, + -578, -575, -572, -568, -565, -562, -558, -555, -552, -549, -545, + -542, -539, -535, -532, -529, -525, -522, -519, -515, -512, -509, + -505, -502, -499, -495, -492, -489, -485, -482, -479, -475, -472, + -469, -465, -462, -459, -455, -452, -449, -446, -442, -439, -436, + -432, -429, -426, -422, -419, -416, -412, -409, -406, -402, -399, + -396, -392, -389, -386, -382, -379, -376, -372, -369, -366, -362, + -359, -356, -353, -349, -346, -343, -339, -336, -333, -329, -326, + -323, -319, -316, -313, -309, -306, -303, -299, -296, -293, -289, + -286, -283, -279, -276, -273, -269, -266, -263, -259, -256, -253, + -250, -246, -243, -240, -236, -233, -230, -226, -223, -220, -216, + -213, -210, -206, -203, -200, -196, -193, -190, -186, -183, -180, + -176, -173, -170, -166, -163, -160, -157, -153, -150, -147, -143, + -140, -137, -133, -130, -127, -123, -120, -117, -113, -110, -107, + -103, -100, -97, -93, -90, -87, -83, -80, -77, -73, -70, + -67, -63, -60, -57, -54, -50, -47, -44, -40, -37, -34, + -30, -27, -24, -20, -17, -14, -10, -7, -4, 0, 3, + 6, 10, 13, 16, 20, 23, 26, 30, 33, 36, 39, + 43, 46, 49, 53, 56, 59, 63, 66, 69, 73, 76, + 79, 83, 86, 89, 93, 96, 99, 103, 106, 109, 113, + 116, 119, 123, 126, 129, 132, 136, 139, 142, 146, 149, + 152, 156, 159, 162, 166, 169, 172, 176, 179, 182, 186, + 189, 192, 196, 199, 202, 206, 209, 212, 216, 219, 222, + 226, 229, 232, 235, 239, 242, 245, 249, 252, 255, 259, + 262, 265, 269, 272, 275, 279, 282, 285, 289, 292, 295, + 299, 302, 305, 309, 312, 315, 319, 322, 325, 328, 332, + 335, 338, 342, 345, 348, 352, 355, 358, 362, 365, 368, + 372, 375, 378, 382, 385, 388, 392, 395, 398, 402, 405, + 408, 412, 415, 418, 422, 425, 428, 431, 435, 438, 441, + 445, 448, 451, 455, 458, 461, 465, 468, 471, 475, 478, + 481, 485, 488, 491, 495, 498, 501, 505, 508, 511, 515, + 518, 521, 524, 528, 531, 534, 538, 541, 544, 548, 551, + 554, 558, 561, 564, 568, 571, 574, 578, 581, 584, 588, + 591, 594, 598, 601, 604, 608, 611, 614, 617, 621, 624, + 627, 631, 634, 637, 641, 644, 647, 651, 654, 657, 661, + 664, 667, 671, 674, 677, 681, 684, 687, 691, 694, 697, + 701, 704, 707, 711, 714, 717, 720, 724, 727, 730, 734, + 737, 740, 744, 747, 750, 754, 757, 760, 764, 767, 770, + 774, 777, 780, 784, 787, 790, 794, 797, 800, 804, 807, + 810, 813, 817, 820, 823, 827, 830, 833, 837, 840, 843, + 847, 850, 853, 857, 860, 863, 867, 870, 873, 877, 880, + 883, 887, 890, 893, 897, 900, 903, 907, 910, 913, 916, + 920, 923, 926, 930, 933, 936, 940, 943, 946, 950, 953, + 956, 960, +}; + +} // namespace ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.h index 1a115aa251..f3b4a11347 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.h @@ -1,120 +1,120 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_STRINGS_CHARCONV_H_ -#define ABSL_STRINGS_CHARCONV_H_ - -#include <system_error> // NOLINT(build/c++11) - +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_CHARCONV_H_ +#define ABSL_STRINGS_CHARCONV_H_ + +#include <system_error> // NOLINT(build/c++11) + #include "y_absl/base/config.h" namespace y_absl { ABSL_NAMESPACE_BEGIN - -// Workalike compatibilty version of std::chars_format from C++17. -// + +// Workalike compatibilty version of std::chars_format from C++17. +// // This is an bitfield enumerator which can be passed to y_absl::from_chars to -// configure the string-to-float conversion. -enum class chars_format { - scientific = 1, - fixed = 2, - hex = 4, - general = fixed | scientific, -}; - -// The return result of a string-to-number conversion. -// -// `ec` will be set to `invalid_argument` if a well-formed number was not found -// at the start of the input range, `result_out_of_range` if a well-formed -// number was found, but it was out of the representable range of the requested -// type, or to std::errc() otherwise. -// -// If a well-formed number was found, `ptr` is set to one past the sequence of -// characters that were successfully parsed. If none was found, `ptr` is set -// to the `first` argument to from_chars. -struct from_chars_result { - const char* ptr; - std::errc ec; -}; - -// Workalike compatibilty version of std::from_chars from C++17. Currently -// this only supports the `double` and `float` types. -// -// This interface incorporates the proposed resolutions for library issues -// DR 3080 and DR 3081. If these are adopted with different wording, -// Abseil's behavior will change to match the standard. (The behavior most -// likely to change is for DR 3081, which says what `value` will be set to in -// the case of overflow and underflow. Code that wants to avoid possible -// breaking changes in this area should not depend on `value` when the returned -// from_chars_result indicates a range error.) -// -// Searches the range [first, last) for the longest matching pattern beginning -// at `first` that represents a floating point number. If one is found, store -// the result in `value`. -// -// The matching pattern format is almost the same as that of strtod(), except +// configure the string-to-float conversion. +enum class chars_format { + scientific = 1, + fixed = 2, + hex = 4, + general = fixed | scientific, +}; + +// The return result of a string-to-number conversion. +// +// `ec` will be set to `invalid_argument` if a well-formed number was not found +// at the start of the input range, `result_out_of_range` if a well-formed +// number was found, but it was out of the representable range of the requested +// type, or to std::errc() otherwise. +// +// If a well-formed number was found, `ptr` is set to one past the sequence of +// characters that were successfully parsed. If none was found, `ptr` is set +// to the `first` argument to from_chars. +struct from_chars_result { + const char* ptr; + std::errc ec; +}; + +// Workalike compatibilty version of std::from_chars from C++17. Currently +// this only supports the `double` and `float` types. +// +// This interface incorporates the proposed resolutions for library issues +// DR 3080 and DR 3081. If these are adopted with different wording, +// Abseil's behavior will change to match the standard. (The behavior most +// likely to change is for DR 3081, which says what `value` will be set to in +// the case of overflow and underflow. Code that wants to avoid possible +// breaking changes in this area should not depend on `value` when the returned +// from_chars_result indicates a range error.) +// +// Searches the range [first, last) for the longest matching pattern beginning +// at `first` that represents a floating point number. If one is found, store +// the result in `value`. +// +// The matching pattern format is almost the same as that of strtod(), except // that (1) C locale is not respected, (2) an initial '+' character in the // input range will never be matched, and (3) leading whitespaces are not // ignored. -// -// If `fmt` is set, it must be one of the enumerator values of the chars_format. -// (This is despite the fact that chars_format is a bitmask type.) If set to -// `scientific`, a matching number must contain an exponent. If set to `fixed`, -// then an exponent will never match. (For example, the string "1e5" will be -// parsed as "1".) If set to `hex`, then a hexadecimal float is parsed in the -// format that strtod() accepts, except that a "0x" prefix is NOT matched. -// (In particular, in `hex` mode, the input "0xff" results in the largest -// matching pattern "0".) +// +// If `fmt` is set, it must be one of the enumerator values of the chars_format. +// (This is despite the fact that chars_format is a bitmask type.) If set to +// `scientific`, a matching number must contain an exponent. If set to `fixed`, +// then an exponent will never match. (For example, the string "1e5" will be +// parsed as "1".) If set to `hex`, then a hexadecimal float is parsed in the +// format that strtod() accepts, except that a "0x" prefix is NOT matched. +// (In particular, in `hex` mode, the input "0xff" results in the largest +// matching pattern "0".) y_absl::from_chars_result from_chars(const char* first, const char* last, - double& value, // NOLINT - chars_format fmt = chars_format::general); - + double& value, // NOLINT + chars_format fmt = chars_format::general); + y_absl::from_chars_result from_chars(const char* first, const char* last, - float& value, // NOLINT - chars_format fmt = chars_format::general); - -// std::chars_format is specified as a bitmask type, which means the following -// operations must be provided: -inline constexpr chars_format operator&(chars_format lhs, chars_format rhs) { - return static_cast<chars_format>(static_cast<int>(lhs) & - static_cast<int>(rhs)); -} -inline constexpr chars_format operator|(chars_format lhs, chars_format rhs) { - return static_cast<chars_format>(static_cast<int>(lhs) | - static_cast<int>(rhs)); -} -inline constexpr chars_format operator^(chars_format lhs, chars_format rhs) { - return static_cast<chars_format>(static_cast<int>(lhs) ^ - static_cast<int>(rhs)); -} -inline constexpr chars_format operator~(chars_format arg) { - return static_cast<chars_format>(~static_cast<int>(arg)); -} -inline chars_format& operator&=(chars_format& lhs, chars_format rhs) { - lhs = lhs & rhs; - return lhs; -} -inline chars_format& operator|=(chars_format& lhs, chars_format rhs) { - lhs = lhs | rhs; - return lhs; -} -inline chars_format& operator^=(chars_format& lhs, chars_format rhs) { - lhs = lhs ^ rhs; - return lhs; -} - + float& value, // NOLINT + chars_format fmt = chars_format::general); + +// std::chars_format is specified as a bitmask type, which means the following +// operations must be provided: +inline constexpr chars_format operator&(chars_format lhs, chars_format rhs) { + return static_cast<chars_format>(static_cast<int>(lhs) & + static_cast<int>(rhs)); +} +inline constexpr chars_format operator|(chars_format lhs, chars_format rhs) { + return static_cast<chars_format>(static_cast<int>(lhs) | + static_cast<int>(rhs)); +} +inline constexpr chars_format operator^(chars_format lhs, chars_format rhs) { + return static_cast<chars_format>(static_cast<int>(lhs) ^ + static_cast<int>(rhs)); +} +inline constexpr chars_format operator~(chars_format arg) { + return static_cast<chars_format>(~static_cast<int>(arg)); +} +inline chars_format& operator&=(chars_format& lhs, chars_format rhs) { + lhs = lhs & rhs; + return lhs; +} +inline chars_format& operator|=(chars_format& lhs, chars_format rhs) { + lhs = lhs | rhs; + return lhs; +} +inline chars_format& operator^=(chars_format& lhs, chars_format rhs) { + lhs = lhs ^ rhs; + return lhs; +} + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_CHARCONV_H_ + +#endif // ABSL_STRINGS_CHARCONV_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.cc index 8c82740608..d97765da3b 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.cc @@ -1,27 +1,27 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/escaping.h" - -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <cstring> -#include <iterator> -#include <limits> + +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <iterator> +#include <limits> #include <util/generic/string.h> - + #include "y_absl/base/internal/endian.h" #include "y_absl/base/internal/raw_logging.h" #include "y_absl/base/internal/unaligned_access.h" @@ -32,918 +32,918 @@ #include "y_absl/strings/str_cat.h" #include "y_absl/strings/str_join.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace { - -// These are used for the leave_nulls_escaped argument to CUnescapeInternal(). -constexpr bool kUnescapeNulls = false; - -inline bool is_octal_digit(char c) { return ('0' <= c) && (c <= '7'); } - -inline int hex_digit_to_int(char c) { - static_assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61, - "Character set must be ASCII."); +namespace { + +// These are used for the leave_nulls_escaped argument to CUnescapeInternal(). +constexpr bool kUnescapeNulls = false; + +inline bool is_octal_digit(char c) { return ('0' <= c) && (c <= '7'); } + +inline int hex_digit_to_int(char c) { + static_assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61, + "Character set must be ASCII."); assert(y_absl::ascii_isxdigit(c)); - int x = static_cast<unsigned char>(c); - if (x > '9') { - x += 9; - } - return x & 0xf; -} - + int x = static_cast<unsigned char>(c); + if (x > '9') { + x += 9; + } + return x & 0xf; +} + inline bool IsSurrogate(char32_t c, y_absl::string_view src, TString* error) { - if (c >= 0xD800 && c <= 0xDFFF) { - if (error) { + if (c >= 0xD800 && c <= 0xDFFF) { + if (error) { *error = y_absl::StrCat("invalid surrogate character (0xD800-DFFF): \\", - src); - } - return true; - } - return false; -} - -// ---------------------------------------------------------------------- -// CUnescapeInternal() -// Implements both CUnescape() and CUnescapeForNullTerminatedString(). -// -// Unescapes C escape sequences and is the reverse of CEscape(). -// -// If 'source' is valid, stores the unescaped string and its size in -// 'dest' and 'dest_len' respectively, and returns true. Otherwise -// returns false and optionally stores the error description in -// 'error'. Set 'error' to nullptr to disable error reporting. -// -// 'dest' should point to a buffer that is at least as big as 'source'. -// 'source' and 'dest' may be the same. -// -// NOTE: any changes to this function must also be reflected in the older -// UnescapeCEscapeSequences(). -// ---------------------------------------------------------------------- + src); + } + return true; + } + return false; +} + +// ---------------------------------------------------------------------- +// CUnescapeInternal() +// Implements both CUnescape() and CUnescapeForNullTerminatedString(). +// +// Unescapes C escape sequences and is the reverse of CEscape(). +// +// If 'source' is valid, stores the unescaped string and its size in +// 'dest' and 'dest_len' respectively, and returns true. Otherwise +// returns false and optionally stores the error description in +// 'error'. Set 'error' to nullptr to disable error reporting. +// +// 'dest' should point to a buffer that is at least as big as 'source'. +// 'source' and 'dest' may be the same. +// +// NOTE: any changes to this function must also be reflected in the older +// UnescapeCEscapeSequences(). +// ---------------------------------------------------------------------- bool CUnescapeInternal(y_absl::string_view source, bool leave_nulls_escaped, char* dest, ptrdiff_t* dest_len, TString* error) { - char* d = dest; - const char* p = source.data(); - const char* end = p + source.size(); - const char* last_byte = end - 1; - - // Small optimization for case where source = dest and there's no escaping - while (p == d && p < end && *p != '\\') p++, d++; - - while (p < end) { - if (*p != '\\') { - *d++ = *p++; - } else { - if (++p > last_byte) { // skip past the '\\' - if (error) *error = "String cannot end with \\"; - return false; - } - switch (*p) { - case 'a': *d++ = '\a'; break; - case 'b': *d++ = '\b'; break; - case 'f': *d++ = '\f'; break; - case 'n': *d++ = '\n'; break; - case 'r': *d++ = '\r'; break; - case 't': *d++ = '\t'; break; - case 'v': *d++ = '\v'; break; - case '\\': *d++ = '\\'; break; - case '?': *d++ = '\?'; break; // \? Who knew? - case '\'': *d++ = '\''; break; - case '"': *d++ = '\"'; break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - // octal digit: 1 to 3 digits - const char* octal_start = p; - unsigned int ch = *p - '0'; - if (p < last_byte && is_octal_digit(p[1])) ch = ch * 8 + *++p - '0'; - if (p < last_byte && is_octal_digit(p[1])) - ch = ch * 8 + *++p - '0'; // now points at last digit - if (ch > 0xff) { - if (error) { - *error = "Value of \\" + + char* d = dest; + const char* p = source.data(); + const char* end = p + source.size(); + const char* last_byte = end - 1; + + // Small optimization for case where source = dest and there's no escaping + while (p == d && p < end && *p != '\\') p++, d++; + + while (p < end) { + if (*p != '\\') { + *d++ = *p++; + } else { + if (++p > last_byte) { // skip past the '\\' + if (error) *error = "String cannot end with \\"; + return false; + } + switch (*p) { + case 'a': *d++ = '\a'; break; + case 'b': *d++ = '\b'; break; + case 'f': *d++ = '\f'; break; + case 'n': *d++ = '\n'; break; + case 'r': *d++ = '\r'; break; + case 't': *d++ = '\t'; break; + case 'v': *d++ = '\v'; break; + case '\\': *d++ = '\\'; break; + case '?': *d++ = '\?'; break; // \? Who knew? + case '\'': *d++ = '\''; break; + case '"': *d++ = '\"'; break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + // octal digit: 1 to 3 digits + const char* octal_start = p; + unsigned int ch = *p - '0'; + if (p < last_byte && is_octal_digit(p[1])) ch = ch * 8 + *++p - '0'; + if (p < last_byte && is_octal_digit(p[1])) + ch = ch * 8 + *++p - '0'; // now points at last digit + if (ch > 0xff) { + if (error) { + *error = "Value of \\" + TString(octal_start, p + 1 - octal_start) + - " exceeds 0xff"; - } - return false; - } - if ((ch == 0) && leave_nulls_escaped) { - // Copy the escape sequence for the null character - const ptrdiff_t octal_size = p + 1 - octal_start; - *d++ = '\\'; + " exceeds 0xff"; + } + return false; + } + if ((ch == 0) && leave_nulls_escaped) { + // Copy the escape sequence for the null character + const ptrdiff_t octal_size = p + 1 - octal_start; + *d++ = '\\'; memmove(d, octal_start, octal_size); - d += octal_size; - break; - } - *d++ = ch; - break; - } - case 'x': - case 'X': { - if (p >= last_byte) { - if (error) *error = "String cannot end with \\x"; - return false; + d += octal_size; + break; + } + *d++ = ch; + break; + } + case 'x': + case 'X': { + if (p >= last_byte) { + if (error) *error = "String cannot end with \\x"; + return false; } else if (!y_absl::ascii_isxdigit(p[1])) { - if (error) *error = "\\x cannot be followed by a non-hex digit"; - return false; - } - unsigned int ch = 0; - const char* hex_start = p; + if (error) *error = "\\x cannot be followed by a non-hex digit"; + return false; + } + unsigned int ch = 0; + const char* hex_start = p; while (p < last_byte && y_absl::ascii_isxdigit(p[1])) - // Arbitrarily many hex digits - ch = (ch << 4) + hex_digit_to_int(*++p); - if (ch > 0xFF) { - if (error) { - *error = "Value of \\" + + // Arbitrarily many hex digits + ch = (ch << 4) + hex_digit_to_int(*++p); + if (ch > 0xFF) { + if (error) { + *error = "Value of \\" + TString(hex_start, p + 1 - hex_start) + - " exceeds 0xff"; - } - return false; - } - if ((ch == 0) && leave_nulls_escaped) { - // Copy the escape sequence for the null character - const ptrdiff_t hex_size = p + 1 - hex_start; - *d++ = '\\'; + " exceeds 0xff"; + } + return false; + } + if ((ch == 0) && leave_nulls_escaped) { + // Copy the escape sequence for the null character + const ptrdiff_t hex_size = p + 1 - hex_start; + *d++ = '\\'; memmove(d, hex_start, hex_size); - d += hex_size; - break; - } - *d++ = ch; - break; - } - case 'u': { - // \uhhhh => convert 4 hex digits to UTF-8 - char32_t rune = 0; - const char* hex_start = p; - if (p + 4 >= end) { - if (error) { - *error = "\\u must be followed by 4 hex digits: \\" + + d += hex_size; + break; + } + *d++ = ch; + break; + } + case 'u': { + // \uhhhh => convert 4 hex digits to UTF-8 + char32_t rune = 0; + const char* hex_start = p; + if (p + 4 >= end) { + if (error) { + *error = "\\u must be followed by 4 hex digits: \\" + TString(hex_start, p + 1 - hex_start); - } - return false; - } - for (int i = 0; i < 4; ++i) { - // Look one char ahead. + } + return false; + } + for (int i = 0; i < 4; ++i) { + // Look one char ahead. if (y_absl::ascii_isxdigit(p[1])) { - rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p. - } else { - if (error) { - *error = "\\u must be followed by 4 hex digits: \\" + + rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p. + } else { + if (error) { + *error = "\\u must be followed by 4 hex digits: \\" + TString(hex_start, p + 1 - hex_start); - } - return false; - } - } - if ((rune == 0) && leave_nulls_escaped) { - // Copy the escape sequence for the null character - *d++ = '\\'; + } + return false; + } + } + if ((rune == 0) && leave_nulls_escaped) { + // Copy the escape sequence for the null character + *d++ = '\\'; memmove(d, hex_start, 5); // u0000 - d += 5; - break; - } + d += 5; + break; + } if (IsSurrogate(rune, y_absl::string_view(hex_start, 5), error)) { - return false; - } - d += strings_internal::EncodeUTF8Char(d, rune); - break; - } - case 'U': { - // \Uhhhhhhhh => convert 8 hex digits to UTF-8 - char32_t rune = 0; - const char* hex_start = p; - if (p + 8 >= end) { - if (error) { - *error = "\\U must be followed by 8 hex digits: \\" + + return false; + } + d += strings_internal::EncodeUTF8Char(d, rune); + break; + } + case 'U': { + // \Uhhhhhhhh => convert 8 hex digits to UTF-8 + char32_t rune = 0; + const char* hex_start = p; + if (p + 8 >= end) { + if (error) { + *error = "\\U must be followed by 8 hex digits: \\" + TString(hex_start, p + 1 - hex_start); - } - return false; - } - for (int i = 0; i < 8; ++i) { - // Look one char ahead. + } + return false; + } + for (int i = 0; i < 8; ++i) { + // Look one char ahead. if (y_absl::ascii_isxdigit(p[1])) { - // Don't change rune until we're sure this - // is within the Unicode limit, but do advance p. - uint32_t newrune = (rune << 4) + hex_digit_to_int(*++p); - if (newrune > 0x10FFFF) { - if (error) { - *error = "Value of \\" + + // Don't change rune until we're sure this + // is within the Unicode limit, but do advance p. + uint32_t newrune = (rune << 4) + hex_digit_to_int(*++p); + if (newrune > 0x10FFFF) { + if (error) { + *error = "Value of \\" + TString(hex_start, p + 1 - hex_start) + - " exceeds Unicode limit (0x10FFFF)"; - } - return false; - } else { - rune = newrune; - } - } else { - if (error) { - *error = "\\U must be followed by 8 hex digits: \\" + + " exceeds Unicode limit (0x10FFFF)"; + } + return false; + } else { + rune = newrune; + } + } else { + if (error) { + *error = "\\U must be followed by 8 hex digits: \\" + TString(hex_start, p + 1 - hex_start); - } - return false; - } - } - if ((rune == 0) && leave_nulls_escaped) { - // Copy the escape sequence for the null character - *d++ = '\\'; + } + return false; + } + } + if ((rune == 0) && leave_nulls_escaped) { + // Copy the escape sequence for the null character + *d++ = '\\'; memmove(d, hex_start, 9); // U00000000 - d += 9; - break; - } + d += 9; + break; + } if (IsSurrogate(rune, y_absl::string_view(hex_start, 9), error)) { - return false; - } - d += strings_internal::EncodeUTF8Char(d, rune); - break; - } - default: { + return false; + } + d += strings_internal::EncodeUTF8Char(d, rune); + break; + } + default: { if (error) *error = TString("Unknown escape sequence: \\") + *p; - return false; - } - } - p++; // read past letter we escaped - } - } - *dest_len = d - dest; - return true; -} - -// ---------------------------------------------------------------------- -// CUnescapeInternal() -// + return false; + } + } + p++; // read past letter we escaped + } + } + *dest_len = d - dest; + return true; +} + +// ---------------------------------------------------------------------- +// CUnescapeInternal() +// // Same as above but uses a TString for output. 'source' and 'dest' -// may be the same. -// ---------------------------------------------------------------------- +// may be the same. +// ---------------------------------------------------------------------- bool CUnescapeInternal(y_absl::string_view source, bool leave_nulls_escaped, TString* dest, TString* error) { - strings_internal::STLStringResizeUninitialized(dest, source.size()); - - ptrdiff_t dest_size; - if (!CUnescapeInternal(source, - leave_nulls_escaped, - &(*dest)[0], - &dest_size, - error)) { - return false; - } - dest->erase(dest_size); - return true; -} - -// ---------------------------------------------------------------------- -// CEscape() -// CHexEscape() -// Utf8SafeCEscape() -// Utf8SafeCHexEscape() -// Escapes 'src' using C-style escape sequences. This is useful for -// preparing query flags. The 'Hex' version uses hexadecimal rather than -// octal sequences. The 'Utf8Safe' version does not touch UTF-8 bytes. -// + strings_internal::STLStringResizeUninitialized(dest, source.size()); + + ptrdiff_t dest_size; + if (!CUnescapeInternal(source, + leave_nulls_escaped, + &(*dest)[0], + &dest_size, + error)) { + return false; + } + dest->erase(dest_size); + return true; +} + +// ---------------------------------------------------------------------- +// CEscape() +// CHexEscape() +// Utf8SafeCEscape() +// Utf8SafeCHexEscape() +// Escapes 'src' using C-style escape sequences. This is useful for +// preparing query flags. The 'Hex' version uses hexadecimal rather than +// octal sequences. The 'Utf8Safe' version does not touch UTF-8 bytes. +// // Escaped chars: \n, \r, \t, ", ', \, and !y_absl::ascii_isprint(). -// ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- TString CEscapeInternal(y_absl::string_view src, bool use_hex, - bool utf8_safe) { + bool utf8_safe) { TString dest; - bool last_hex_escape = false; // true if last output char was \xNN. - - for (unsigned char c : src) { - bool is_hex_escape = false; - switch (c) { - case '\n': dest.append("\\" "n"); break; - case '\r': dest.append("\\" "r"); break; - case '\t': dest.append("\\" "t"); break; - case '\"': dest.append("\\" "\""); break; - case '\'': dest.append("\\" "'"); break; - case '\\': dest.append("\\" "\\"); break; - default: - // Note that if we emit \xNN and the src character after that is a hex - // digit then that digit must be escaped too to prevent it being - // interpreted as part of the character code by C. - if ((!utf8_safe || c < 0x80) && + bool last_hex_escape = false; // true if last output char was \xNN. + + for (unsigned char c : src) { + bool is_hex_escape = false; + switch (c) { + case '\n': dest.append("\\" "n"); break; + case '\r': dest.append("\\" "r"); break; + case '\t': dest.append("\\" "t"); break; + case '\"': dest.append("\\" "\""); break; + case '\'': dest.append("\\" "'"); break; + case '\\': dest.append("\\" "\\"); break; + default: + // Note that if we emit \xNN and the src character after that is a hex + // digit then that digit must be escaped too to prevent it being + // interpreted as part of the character code by C. + if ((!utf8_safe || c < 0x80) && (!y_absl::ascii_isprint(c) || (last_hex_escape && y_absl::ascii_isxdigit(c)))) { - if (use_hex) { - dest.append("\\" "x"); - dest.push_back(numbers_internal::kHexChar[c / 16]); - dest.push_back(numbers_internal::kHexChar[c % 16]); - is_hex_escape = true; - } else { - dest.append("\\"); - dest.push_back(numbers_internal::kHexChar[c / 64]); - dest.push_back(numbers_internal::kHexChar[(c % 64) / 8]); - dest.push_back(numbers_internal::kHexChar[c % 8]); - } - } else { - dest.push_back(c); - break; - } - } - last_hex_escape = is_hex_escape; - } - - return dest; -} - -/* clang-format off */ -constexpr char c_escaped_len[256] = { - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", ' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -}; -/* clang-format on */ - -// Calculates the length of the C-style escaped version of 'src'. -// Assumes that non-printable characters are escaped using octal sequences, and -// that UTF-8 bytes are not handled specially. + if (use_hex) { + dest.append("\\" "x"); + dest.push_back(numbers_internal::kHexChar[c / 16]); + dest.push_back(numbers_internal::kHexChar[c % 16]); + is_hex_escape = true; + } else { + dest.append("\\"); + dest.push_back(numbers_internal::kHexChar[c / 64]); + dest.push_back(numbers_internal::kHexChar[(c % 64) / 8]); + dest.push_back(numbers_internal::kHexChar[c % 8]); + } + } else { + dest.push_back(c); + break; + } + } + last_hex_escape = is_hex_escape; + } + + return dest; +} + +/* clang-format off */ +constexpr char c_escaped_len[256] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", ' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o' + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +}; +/* clang-format on */ + +// Calculates the length of the C-style escaped version of 'src'. +// Assumes that non-printable characters are escaped using octal sequences, and +// that UTF-8 bytes are not handled specially. inline size_t CEscapedLength(y_absl::string_view src) { - size_t escaped_len = 0; - for (unsigned char c : src) escaped_len += c_escaped_len[c]; - return escaped_len; -} - + size_t escaped_len = 0; + for (unsigned char c : src) escaped_len += c_escaped_len[c]; + return escaped_len; +} + void CEscapeAndAppendInternal(y_absl::string_view src, TString* dest) { - size_t escaped_len = CEscapedLength(src); - if (escaped_len == src.size()) { - dest->append(src.data(), src.size()); - return; - } - - size_t cur_dest_len = dest->size(); - strings_internal::STLStringResizeUninitialized(dest, - cur_dest_len + escaped_len); - char* append_ptr = &(*dest)[cur_dest_len]; - - for (unsigned char c : src) { - int char_len = c_escaped_len[c]; - if (char_len == 1) { - *append_ptr++ = c; - } else if (char_len == 2) { - switch (c) { - case '\n': - *append_ptr++ = '\\'; - *append_ptr++ = 'n'; - break; - case '\r': - *append_ptr++ = '\\'; - *append_ptr++ = 'r'; - break; - case '\t': - *append_ptr++ = '\\'; - *append_ptr++ = 't'; - break; - case '\"': - *append_ptr++ = '\\'; - *append_ptr++ = '\"'; - break; - case '\'': - *append_ptr++ = '\\'; - *append_ptr++ = '\''; - break; - case '\\': - *append_ptr++ = '\\'; - *append_ptr++ = '\\'; - break; - } - } else { - *append_ptr++ = '\\'; - *append_ptr++ = '0' + c / 64; - *append_ptr++ = '0' + (c % 64) / 8; - *append_ptr++ = '0' + c % 8; - } - } -} - -bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest, - size_t szdest, const signed char* unbase64, - size_t* len) { - static const char kPad64Equals = '='; - static const char kPad64Dot = '.'; - - size_t destidx = 0; - int decode = 0; - int state = 0; - unsigned int ch = 0; - unsigned int temp = 0; - - // If "char" is signed by default, using *src as an array index results in - // accessing negative array elements. Treat the input as a pointer to - // unsigned char to avoid this. - const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param); - - // The GET_INPUT macro gets the next input character, skipping - // over any whitespace, and stopping when we reach the end of the + size_t escaped_len = CEscapedLength(src); + if (escaped_len == src.size()) { + dest->append(src.data(), src.size()); + return; + } + + size_t cur_dest_len = dest->size(); + strings_internal::STLStringResizeUninitialized(dest, + cur_dest_len + escaped_len); + char* append_ptr = &(*dest)[cur_dest_len]; + + for (unsigned char c : src) { + int char_len = c_escaped_len[c]; + if (char_len == 1) { + *append_ptr++ = c; + } else if (char_len == 2) { + switch (c) { + case '\n': + *append_ptr++ = '\\'; + *append_ptr++ = 'n'; + break; + case '\r': + *append_ptr++ = '\\'; + *append_ptr++ = 'r'; + break; + case '\t': + *append_ptr++ = '\\'; + *append_ptr++ = 't'; + break; + case '\"': + *append_ptr++ = '\\'; + *append_ptr++ = '\"'; + break; + case '\'': + *append_ptr++ = '\\'; + *append_ptr++ = '\''; + break; + case '\\': + *append_ptr++ = '\\'; + *append_ptr++ = '\\'; + break; + } + } else { + *append_ptr++ = '\\'; + *append_ptr++ = '0' + c / 64; + *append_ptr++ = '0' + (c % 64) / 8; + *append_ptr++ = '0' + c % 8; + } + } +} + +bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest, + size_t szdest, const signed char* unbase64, + size_t* len) { + static const char kPad64Equals = '='; + static const char kPad64Dot = '.'; + + size_t destidx = 0; + int decode = 0; + int state = 0; + unsigned int ch = 0; + unsigned int temp = 0; + + // If "char" is signed by default, using *src as an array index results in + // accessing negative array elements. Treat the input as a pointer to + // unsigned char to avoid this. + const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param); + + // The GET_INPUT macro gets the next input character, skipping + // over any whitespace, and stopping when we reach the end of the // string or when we read any non-data character. The arguments are - // an arbitrary identifier (used as a label for goto) and the number - // of data bytes that must remain in the input to avoid aborting the - // loop. -#define GET_INPUT(label, remain) \ - label: \ - --szsrc; \ - ch = *src++; \ - decode = unbase64[ch]; \ - if (decode < 0) { \ + // an arbitrary identifier (used as a label for goto) and the number + // of data bytes that must remain in the input to avoid aborting the + // loop. +#define GET_INPUT(label, remain) \ + label: \ + --szsrc; \ + ch = *src++; \ + decode = unbase64[ch]; \ + if (decode < 0) { \ if (y_absl::ascii_isspace(ch) && szsrc >= remain) goto label; \ - state = 4 - remain; \ - break; \ - } - - // if dest is null, we're just checking to see if it's legal input - // rather than producing output. (I suspect this could just be done - // with a regexp...). We duplicate the loop so this test can be - // outside it instead of in every iteration. - - if (dest) { - // This loop consumes 4 input bytes and produces 3 output bytes - // per iteration. We can't know at the start that there is enough + state = 4 - remain; \ + break; \ + } + + // if dest is null, we're just checking to see if it's legal input + // rather than producing output. (I suspect this could just be done + // with a regexp...). We duplicate the loop so this test can be + // outside it instead of in every iteration. + + if (dest) { + // This loop consumes 4 input bytes and produces 3 output bytes + // per iteration. We can't know at the start that there is enough // data left in the string for a full iteration, so the loop may - // break out in the middle; if so 'state' will be set to the - // number of input bytes read. - - while (szsrc >= 4) { - // We'll start by optimistically assuming that the next four + // break out in the middle; if so 'state' will be set to the + // number of input bytes read. + + while (szsrc >= 4) { + // We'll start by optimistically assuming that the next four // bytes of the string (src[0..3]) are four good data bytes - // (that is, no nulls, whitespace, padding chars, or illegal - // chars). We need to test src[0..2] for nulls individually - // before constructing temp to preserve the property that we + // (that is, no nulls, whitespace, padding chars, or illegal + // chars). We need to test src[0..2] for nulls individually + // before constructing temp to preserve the property that we // never read past a null in the string (no matter how long // szsrc claims the string is). - - if (!src[0] || !src[1] || !src[2] || - ((temp = ((unsigned(unbase64[src[0]]) << 18) | - (unsigned(unbase64[src[1]]) << 12) | - (unsigned(unbase64[src[2]]) << 6) | - (unsigned(unbase64[src[3]])))) & - 0x80000000)) { - // Iff any of those four characters was bad (null, illegal, - // whitespace, padding), then temp's high bit will be set - // (because unbase64[] is -1 for all bad characters). - // - // We'll back up and resort to the slower decoder, which knows - // how to handle those cases. - - GET_INPUT(first, 4); - temp = decode; - GET_INPUT(second, 3); - temp = (temp << 6) | decode; - GET_INPUT(third, 2); - temp = (temp << 6) | decode; - GET_INPUT(fourth, 1); - temp = (temp << 6) | decode; - } else { - // We really did have four good data bytes, so advance four + + if (!src[0] || !src[1] || !src[2] || + ((temp = ((unsigned(unbase64[src[0]]) << 18) | + (unsigned(unbase64[src[1]]) << 12) | + (unsigned(unbase64[src[2]]) << 6) | + (unsigned(unbase64[src[3]])))) & + 0x80000000)) { + // Iff any of those four characters was bad (null, illegal, + // whitespace, padding), then temp's high bit will be set + // (because unbase64[] is -1 for all bad characters). + // + // We'll back up and resort to the slower decoder, which knows + // how to handle those cases. + + GET_INPUT(first, 4); + temp = decode; + GET_INPUT(second, 3); + temp = (temp << 6) | decode; + GET_INPUT(third, 2); + temp = (temp << 6) | decode; + GET_INPUT(fourth, 1); + temp = (temp << 6) | decode; + } else { + // We really did have four good data bytes, so advance four // characters in the string. - - szsrc -= 4; - src += 4; - } - - // temp has 24 bits of input, so write that out as three bytes. - - if (destidx + 3 > szdest) return false; - dest[destidx + 2] = temp; - temp >>= 8; - dest[destidx + 1] = temp; - temp >>= 8; - dest[destidx] = temp; - destidx += 3; - } - } else { - while (szsrc >= 4) { - if (!src[0] || !src[1] || !src[2] || - ((temp = ((unsigned(unbase64[src[0]]) << 18) | - (unsigned(unbase64[src[1]]) << 12) | - (unsigned(unbase64[src[2]]) << 6) | - (unsigned(unbase64[src[3]])))) & - 0x80000000)) { - GET_INPUT(first_no_dest, 4); - GET_INPUT(second_no_dest, 3); - GET_INPUT(third_no_dest, 2); - GET_INPUT(fourth_no_dest, 1); - } else { - szsrc -= 4; - src += 4; - } - destidx += 3; - } - } - -#undef GET_INPUT - - // if the loop terminated because we read a bad character, return - // now. - if (decode < 0 && ch != kPad64Equals && ch != kPad64Dot && + + szsrc -= 4; + src += 4; + } + + // temp has 24 bits of input, so write that out as three bytes. + + if (destidx + 3 > szdest) return false; + dest[destidx + 2] = temp; + temp >>= 8; + dest[destidx + 1] = temp; + temp >>= 8; + dest[destidx] = temp; + destidx += 3; + } + } else { + while (szsrc >= 4) { + if (!src[0] || !src[1] || !src[2] || + ((temp = ((unsigned(unbase64[src[0]]) << 18) | + (unsigned(unbase64[src[1]]) << 12) | + (unsigned(unbase64[src[2]]) << 6) | + (unsigned(unbase64[src[3]])))) & + 0x80000000)) { + GET_INPUT(first_no_dest, 4); + GET_INPUT(second_no_dest, 3); + GET_INPUT(third_no_dest, 2); + GET_INPUT(fourth_no_dest, 1); + } else { + szsrc -= 4; + src += 4; + } + destidx += 3; + } + } + +#undef GET_INPUT + + // if the loop terminated because we read a bad character, return + // now. + if (decode < 0 && ch != kPad64Equals && ch != kPad64Dot && !y_absl::ascii_isspace(ch)) - return false; - - if (ch == kPad64Equals || ch == kPad64Dot) { - // if we stopped by hitting an '=' or '.', un-read that character -- we'll - // look at it again when we count to check for the proper number of - // equals signs at the end. - ++szsrc; - --src; - } else { - // This loop consumes 1 input byte per iteration. It's used to - // clean up the 0-3 input bytes remaining when the first, faster - // loop finishes. 'temp' contains the data from 'state' input - // characters read by the first loop. - while (szsrc > 0) { - --szsrc; - ch = *src++; - decode = unbase64[ch]; - if (decode < 0) { + return false; + + if (ch == kPad64Equals || ch == kPad64Dot) { + // if we stopped by hitting an '=' or '.', un-read that character -- we'll + // look at it again when we count to check for the proper number of + // equals signs at the end. + ++szsrc; + --src; + } else { + // This loop consumes 1 input byte per iteration. It's used to + // clean up the 0-3 input bytes remaining when the first, faster + // loop finishes. 'temp' contains the data from 'state' input + // characters read by the first loop. + while (szsrc > 0) { + --szsrc; + ch = *src++; + decode = unbase64[ch]; + if (decode < 0) { if (y_absl::ascii_isspace(ch)) { - continue; - } else if (ch == kPad64Equals || ch == kPad64Dot) { - // back up one character; we'll read it again when we check - // for the correct number of pad characters at the end. - ++szsrc; - --src; - break; - } else { - return false; - } - } - - // Each input character gives us six bits of output. - temp = (temp << 6) | decode; - ++state; - if (state == 4) { - // If we've accumulated 24 bits of output, write that out as - // three bytes. - if (dest) { - if (destidx + 3 > szdest) return false; - dest[destidx + 2] = temp; - temp >>= 8; - dest[destidx + 1] = temp; - temp >>= 8; - dest[destidx] = temp; - } - destidx += 3; - state = 0; - temp = 0; - } - } - } - - // Process the leftover data contained in 'temp' at the end of the input. - int expected_equals = 0; - switch (state) { - case 0: - // Nothing left over; output is a multiple of 3 bytes. - break; - - case 1: - // Bad input; we have 6 bits left over. - return false; - - case 2: - // Produce one more output byte from the 12 input bits we have left. - if (dest) { - if (destidx + 1 > szdest) return false; - temp >>= 4; - dest[destidx] = temp; - } - ++destidx; - expected_equals = 2; - break; - - case 3: - // Produce two more output bytes from the 18 input bits we have left. - if (dest) { - if (destidx + 2 > szdest) return false; - temp >>= 2; - dest[destidx + 1] = temp; - temp >>= 8; - dest[destidx] = temp; - } - destidx += 2; - expected_equals = 1; - break; - - default: - // state should have no other values at this point. - ABSL_RAW_LOG(FATAL, "This can't happen; base64 decoder state = %d", - state); - } - + continue; + } else if (ch == kPad64Equals || ch == kPad64Dot) { + // back up one character; we'll read it again when we check + // for the correct number of pad characters at the end. + ++szsrc; + --src; + break; + } else { + return false; + } + } + + // Each input character gives us six bits of output. + temp = (temp << 6) | decode; + ++state; + if (state == 4) { + // If we've accumulated 24 bits of output, write that out as + // three bytes. + if (dest) { + if (destidx + 3 > szdest) return false; + dest[destidx + 2] = temp; + temp >>= 8; + dest[destidx + 1] = temp; + temp >>= 8; + dest[destidx] = temp; + } + destidx += 3; + state = 0; + temp = 0; + } + } + } + + // Process the leftover data contained in 'temp' at the end of the input. + int expected_equals = 0; + switch (state) { + case 0: + // Nothing left over; output is a multiple of 3 bytes. + break; + + case 1: + // Bad input; we have 6 bits left over. + return false; + + case 2: + // Produce one more output byte from the 12 input bits we have left. + if (dest) { + if (destidx + 1 > szdest) return false; + temp >>= 4; + dest[destidx] = temp; + } + ++destidx; + expected_equals = 2; + break; + + case 3: + // Produce two more output bytes from the 18 input bits we have left. + if (dest) { + if (destidx + 2 > szdest) return false; + temp >>= 2; + dest[destidx + 1] = temp; + temp >>= 8; + dest[destidx] = temp; + } + destidx += 2; + expected_equals = 1; + break; + + default: + // state should have no other values at this point. + ABSL_RAW_LOG(FATAL, "This can't happen; base64 decoder state = %d", + state); + } + // The remainder of the string should be all whitespace, mixed with - // exactly 0 equals signs, or exactly 'expected_equals' equals - // signs. (Always accepting 0 equals signs is an Abseil extension - // not covered in the RFC, as is accepting dot as the pad character.) - - int equals = 0; - while (szsrc > 0) { - if (*src == kPad64Equals || *src == kPad64Dot) - ++equals; + // exactly 0 equals signs, or exactly 'expected_equals' equals + // signs. (Always accepting 0 equals signs is an Abseil extension + // not covered in the RFC, as is accepting dot as the pad character.) + + int equals = 0; + while (szsrc > 0) { + if (*src == kPad64Equals || *src == kPad64Dot) + ++equals; else if (!y_absl::ascii_isspace(*src)) - return false; - --szsrc; - ++src; - } - - const bool ok = (equals == 0 || equals == expected_equals); - if (ok) *len = destidx; - return ok; -} - -// The arrays below were generated by the following code -// #include <sys/time.h> -// #include <stdlib.h> -// #include <string.h> -// main() -// { -// static const char Base64[] = -// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -// char* pos; -// int idx, i, j; -// printf(" "); -// for (i = 0; i < 255; i += 8) { -// for (j = i; j < i + 8; j++) { -// pos = strchr(Base64, j); -// if ((pos == nullptr) || (j == 0)) -// idx = -1; -// else -// idx = pos - Base64; -// if (idx == -1) -// printf(" %2d, ", idx); -// else -// printf(" %2d/*%c*/,", idx, j); -// } -// printf("\n "); -// } -// } -// -// where the value of "Base64[]" was replaced by one of the base-64 conversion -// tables from the functions below. -/* clang-format off */ -constexpr signed char kUnBase64[] = { - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, - 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, - 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, - -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, - 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, - 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, - 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, - -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, - 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, - 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, - 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 -}; - -constexpr signed char kUnWebSafeBase64[] = { - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 62/*-*/, -1, -1, - 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, - 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, - -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, - 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, - 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, - 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/, - -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, - 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, - 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, - 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 -}; -/* clang-format on */ - -constexpr char kWebSafeBase64Chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; - -template <typename String> -bool Base64UnescapeInternal(const char* src, size_t slen, String* dest, - const signed char* unbase64) { + return false; + --szsrc; + ++src; + } + + const bool ok = (equals == 0 || equals == expected_equals); + if (ok) *len = destidx; + return ok; +} + +// The arrays below were generated by the following code +// #include <sys/time.h> +// #include <stdlib.h> +// #include <string.h> +// main() +// { +// static const char Base64[] = +// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +// char* pos; +// int idx, i, j; +// printf(" "); +// for (i = 0; i < 255; i += 8) { +// for (j = i; j < i + 8; j++) { +// pos = strchr(Base64, j); +// if ((pos == nullptr) || (j == 0)) +// idx = -1; +// else +// idx = pos - Base64; +// if (idx == -1) +// printf(" %2d, ", idx); +// else +// printf(" %2d/*%c*/,", idx, j); +// } +// printf("\n "); +// } +// } +// +// where the value of "Base64[]" was replaced by one of the base-64 conversion +// tables from the functions below. +/* clang-format off */ +constexpr signed char kUnBase64[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, + 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, + 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, + -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, + 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, + 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, + 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, + -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, + 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, + 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, + 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +constexpr signed char kUnWebSafeBase64[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 62/*-*/, -1, -1, + 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, + 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, + -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, + 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, + 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, + 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/, + -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, + 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, + 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, + 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; +/* clang-format on */ + +constexpr char kWebSafeBase64Chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +template <typename String> +bool Base64UnescapeInternal(const char* src, size_t slen, String* dest, + const signed char* unbase64) { // Determine the size of the output string. Base64 encodes every 3 bytes into - // 4 characters. any leftover chars are added directly for good measure. - // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548 - const size_t dest_len = 3 * (slen / 4) + (slen % 4); - - strings_internal::STLStringResizeUninitialized(dest, dest_len); - - // We are getting the destination buffer by getting the beginning of the + // 4 characters. any leftover chars are added directly for good measure. + // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548 + const size_t dest_len = 3 * (slen / 4) + (slen % 4); + + strings_internal::STLStringResizeUninitialized(dest, dest_len); + + // We are getting the destination buffer by getting the beginning of the // string and converting it into a char *. - size_t len; - const bool ok = - Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len); - if (!ok) { - dest->clear(); - return false; - } - - // could be shorter if there was padding - assert(len <= dest_len); - dest->erase(len); - - return true; -} - -/* clang-format off */ + size_t len; + const bool ok = + Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len); + if (!ok) { + dest->clear(); + return false; + } + + // could be shorter if there was padding + assert(len <= dest_len); + dest->erase(len); + + return true; +} + +/* clang-format off */ constexpr char kHexValueLenient[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -/* clang-format on */ - -// This is a templated function so that T can be either a char* -// or a string. This works because we use the [] operator to access -// individual characters at a time. -template <typename T> -void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) { - for (int i = 0; i < num; i++) { +}; + +/* clang-format on */ + +// This is a templated function so that T can be either a char* +// or a string. This works because we use the [] operator to access +// individual characters at a time. +template <typename T> +void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) { + for (int i = 0; i < num; i++) { to[i] = (kHexValueLenient[from[i * 2] & 0xFF] << 4) + (kHexValueLenient[from[i * 2 + 1] & 0xFF]); - } -} - -// This is a templated function so that T can be either a char* or a + } +} + +// This is a templated function so that T can be either a char* or a // TString. -template <typename T> -void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) { - auto dest_ptr = &dest[0]; - for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) { - const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2]; - std::copy(hex_p, hex_p + 2, dest_ptr); - } -} - -} // namespace - -// ---------------------------------------------------------------------- -// CUnescape() -// -// See CUnescapeInternal() for implementation details. -// ---------------------------------------------------------------------- +template <typename T> +void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) { + auto dest_ptr = &dest[0]; + for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) { + const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2]; + std::copy(hex_p, hex_p + 2, dest_ptr); + } +} + +} // namespace + +// ---------------------------------------------------------------------- +// CUnescape() +// +// See CUnescapeInternal() for implementation details. +// ---------------------------------------------------------------------- bool CUnescape(y_absl::string_view source, TString* dest, TString* error) { - return CUnescapeInternal(source, kUnescapeNulls, dest, error); -} - + return CUnescapeInternal(source, kUnescapeNulls, dest, error); +} + TString CEscape(y_absl::string_view src) { TString dest; - CEscapeAndAppendInternal(src, &dest); - return dest; -} - + CEscapeAndAppendInternal(src, &dest); + return dest; +} + TString CHexEscape(y_absl::string_view src) { - return CEscapeInternal(src, true, false); -} - + return CEscapeInternal(src, true, false); +} + TString Utf8SafeCEscape(y_absl::string_view src) { - return CEscapeInternal(src, false, true); -} - + return CEscapeInternal(src, false, true); +} + TString Utf8SafeCHexEscape(y_absl::string_view src) { - return CEscapeInternal(src, true, true); -} - -// ---------------------------------------------------------------------- -// Base64Unescape() - base64 decoder -// Base64Escape() - base64 encoder -// WebSafeBase64Unescape() - Google's variation of base64 decoder -// WebSafeBase64Escape() - Google's variation of base64 encoder -// -// Check out -// http://tools.ietf.org/html/rfc2045 for formal description, but what we -// care about is that... -// Take the encoded stuff in groups of 4 characters and turn each -// character into a code 0 to 63 thus: -// A-Z map to 0 to 25 -// a-z map to 26 to 51 -// 0-9 map to 52 to 61 -// +(- for WebSafe) maps to 62 -// /(_ for WebSafe) maps to 63 -// There will be four numbers, all less than 64 which can be represented -// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively). -// Arrange the 6 digit binary numbers into three bytes as such: -// aaaaaabb bbbbcccc ccdddddd -// Equals signs (one or two) are used at the end of the encoded block to -// indicate that the text was not an integer multiple of three bytes long. -// ---------------------------------------------------------------------- - + return CEscapeInternal(src, true, true); +} + +// ---------------------------------------------------------------------- +// Base64Unescape() - base64 decoder +// Base64Escape() - base64 encoder +// WebSafeBase64Unescape() - Google's variation of base64 decoder +// WebSafeBase64Escape() - Google's variation of base64 encoder +// +// Check out +// http://tools.ietf.org/html/rfc2045 for formal description, but what we +// care about is that... +// Take the encoded stuff in groups of 4 characters and turn each +// character into a code 0 to 63 thus: +// A-Z map to 0 to 25 +// a-z map to 26 to 51 +// 0-9 map to 52 to 61 +// +(- for WebSafe) maps to 62 +// /(_ for WebSafe) maps to 63 +// There will be four numbers, all less than 64 which can be represented +// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively). +// Arrange the 6 digit binary numbers into three bytes as such: +// aaaaaabb bbbbcccc ccdddddd +// Equals signs (one or two) are used at the end of the encoded block to +// indicate that the text was not an integer multiple of three bytes long. +// ---------------------------------------------------------------------- + bool Base64Unescape(y_absl::string_view src, TString* dest) { - return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64); -} - + return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64); +} + bool WebSafeBase64Unescape(y_absl::string_view src, TString* dest) { - return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64); -} - + return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64); +} + void Base64Escape(y_absl::string_view src, TString* dest) { strings_internal::Base64EscapeInternal( reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest, true, strings_internal::kBase64Chars); -} - +} + void WebSafeBase64Escape(y_absl::string_view src, TString* dest) { strings_internal::Base64EscapeInternal( reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest, false, kWebSafeBase64Chars); -} - +} + TString Base64Escape(y_absl::string_view src) { TString dest; strings_internal::Base64EscapeInternal( reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest, true, strings_internal::kBase64Chars); - return dest; -} - + return dest; +} + TString WebSafeBase64Escape(y_absl::string_view src) { TString dest; strings_internal::Base64EscapeInternal( reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest, false, kWebSafeBase64Chars); - return dest; -} - + return dest; +} + TString HexStringToBytes(y_absl::string_view from) { TString result; - const auto num = from.size() / 2; - strings_internal::STLStringResizeUninitialized(&result, num); + const auto num = from.size() / 2; + strings_internal::STLStringResizeUninitialized(&result, num); y_absl::HexStringToBytesInternal<TString&>(from.data(), result, num); - return result; -} - + return result; +} + TString BytesToHexString(y_absl::string_view from) { TString result; - strings_internal::STLStringResizeUninitialized(&result, 2 * from.size()); + strings_internal::STLStringResizeUninitialized(&result, 2 * from.size()); y_absl::BytesToHexStringInternal<TString&>( - reinterpret_cast<const unsigned char*>(from.data()), result, from.size()); - return result; -} - + reinterpret_cast<const unsigned char*>(from.data()), result, from.size()); + return result; +} + ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.h index 8868b87879..e7428c197a 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.h @@ -1,164 +1,164 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: escaping.h -// ----------------------------------------------------------------------------- -// -// This header file contains string utilities involved in escaping and -// unescaping strings in various ways. - -#ifndef ABSL_STRINGS_ESCAPING_H_ -#define ABSL_STRINGS_ESCAPING_H_ - -#include <cstddef> +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: escaping.h +// ----------------------------------------------------------------------------- +// +// This header file contains string utilities involved in escaping and +// unescaping strings in various ways. + +#ifndef ABSL_STRINGS_ESCAPING_H_ +#define ABSL_STRINGS_ESCAPING_H_ + +#include <cstddef> #include <util/generic/string.h> -#include <vector> - +#include <vector> + #include "y_absl/base/macros.h" #include "y_absl/strings/ascii.h" #include "y_absl/strings/str_join.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -// CUnescape() -// -// Unescapes a `source` string and copies it into `dest`, rewriting C-style -// escape sequences (https://en.cppreference.com/w/cpp/language/escape) into -// their proper code point equivalents, returning `true` if successful. -// -// The following unescape sequences can be handled: -// -// * ASCII escape sequences ('\n','\r','\\', etc.) to their ASCII equivalents -// * Octal escape sequences ('\nnn') to byte nnn. The unescaped value must -// resolve to a single byte or an error will occur. E.g. values greater than -// 0xff will produce an error. -// * Hexadecimal escape sequences ('\xnn') to byte nn. While an arbitrary -// number of following digits are allowed, the unescaped value must resolve -// to a single byte or an error will occur. E.g. '\x0045' is equivalent to -// '\x45', but '\x1234' will produce an error. -// * Unicode escape sequences ('\unnnn' for exactly four hex digits or -// '\Unnnnnnnn' for exactly eight hex digits, which will be encoded in -// UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and -// 0x99). -// -// If any errors are encountered, this function returns `false`, leaving the -// `dest` output parameter in an unspecified state, and stores the first -// encountered error in `error`. To disable error reporting, set `error` to -// `nullptr` or use the overload with no error reporting below. -// -// Example: -// + +// CUnescape() +// +// Unescapes a `source` string and copies it into `dest`, rewriting C-style +// escape sequences (https://en.cppreference.com/w/cpp/language/escape) into +// their proper code point equivalents, returning `true` if successful. +// +// The following unescape sequences can be handled: +// +// * ASCII escape sequences ('\n','\r','\\', etc.) to their ASCII equivalents +// * Octal escape sequences ('\nnn') to byte nnn. The unescaped value must +// resolve to a single byte or an error will occur. E.g. values greater than +// 0xff will produce an error. +// * Hexadecimal escape sequences ('\xnn') to byte nn. While an arbitrary +// number of following digits are allowed, the unescaped value must resolve +// to a single byte or an error will occur. E.g. '\x0045' is equivalent to +// '\x45', but '\x1234' will produce an error. +// * Unicode escape sequences ('\unnnn' for exactly four hex digits or +// '\Unnnnnnnn' for exactly eight hex digits, which will be encoded in +// UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and +// 0x99). +// +// If any errors are encountered, this function returns `false`, leaving the +// `dest` output parameter in an unspecified state, and stores the first +// encountered error in `error`. To disable error reporting, set `error` to +// `nullptr` or use the overload with no error reporting below. +// +// Example: +// // TString s = "foo\\rbar\\nbaz\\t"; // TString unescaped_s; // if (!y_absl::CUnescape(s, &unescaped_s) { -// ... -// } -// EXPECT_EQ(unescaped_s, "foo\rbar\nbaz\t"); +// ... +// } +// EXPECT_EQ(unescaped_s, "foo\rbar\nbaz\t"); bool CUnescape(y_absl::string_view source, TString* dest, TString* error); - -// Overload of `CUnescape()` with no error reporting. + +// Overload of `CUnescape()` with no error reporting. inline bool CUnescape(y_absl::string_view source, TString* dest) { - return CUnescape(source, dest, nullptr); -} - -// CEscape() -// -// Escapes a 'src' string using C-style escapes sequences -// (https://en.cppreference.com/w/cpp/language/escape), escaping other -// non-printable/non-whitespace bytes as octal sequences (e.g. "\377"). -// -// Example: -// + return CUnescape(source, dest, nullptr); +} + +// CEscape() +// +// Escapes a 'src' string using C-style escapes sequences +// (https://en.cppreference.com/w/cpp/language/escape), escaping other +// non-printable/non-whitespace bytes as octal sequences (e.g. "\377"). +// +// Example: +// // TString s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n"; // TString escaped_s = y_absl::CEscape(s); -// EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\010\\t\\n\\013\\014\\r\\n"); +// EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\010\\t\\n\\013\\014\\r\\n"); TString CEscape(y_absl::string_view src); - -// CHexEscape() -// -// Escapes a 'src' string using C-style escape sequences, escaping -// other non-printable/non-whitespace bytes as hexadecimal sequences (e.g. -// "\xFF"). -// -// Example: -// + +// CHexEscape() +// +// Escapes a 'src' string using C-style escape sequences, escaping +// other non-printable/non-whitespace bytes as hexadecimal sequences (e.g. +// "\xFF"). +// +// Example: +// // TString s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n"; // TString escaped_s = y_absl::CHexEscape(s); -// EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\x08\\t\\n\\x0b\\x0c\\r\\n"); +// EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\x08\\t\\n\\x0b\\x0c\\r\\n"); TString CHexEscape(y_absl::string_view src); - -// Utf8SafeCEscape() -// -// Escapes a 'src' string using C-style escape sequences, escaping bytes as -// octal sequences, and passing through UTF-8 characters without conversion. -// I.e., when encountering any bytes with their high bit set, this function -// will not escape those values, whether or not they are valid UTF-8. + +// Utf8SafeCEscape() +// +// Escapes a 'src' string using C-style escape sequences, escaping bytes as +// octal sequences, and passing through UTF-8 characters without conversion. +// I.e., when encountering any bytes with their high bit set, this function +// will not escape those values, whether or not they are valid UTF-8. TString Utf8SafeCEscape(y_absl::string_view src); - -// Utf8SafeCHexEscape() -// -// Escapes a 'src' string using C-style escape sequences, escaping bytes as -// hexadecimal sequences, and passing through UTF-8 characters without -// conversion. + +// Utf8SafeCHexEscape() +// +// Escapes a 'src' string using C-style escape sequences, escaping bytes as +// hexadecimal sequences, and passing through UTF-8 characters without +// conversion. TString Utf8SafeCHexEscape(y_absl::string_view src); - -// Base64Unescape() -// -// Converts a `src` string encoded in Base64 to its binary equivalent, writing -// it to a `dest` buffer, returning `true` on success. If `src` contains invalid -// characters, `dest` is cleared and returns `false`. + +// Base64Unescape() +// +// Converts a `src` string encoded in Base64 to its binary equivalent, writing +// it to a `dest` buffer, returning `true` on success. If `src` contains invalid +// characters, `dest` is cleared and returns `false`. bool Base64Unescape(y_absl::string_view src, TString* dest); - -// WebSafeBase64Unescape() -// -// Converts a `src` string encoded in Base64 to its binary equivalent, writing -// it to a `dest` buffer, but using '-' instead of '+', and '_' instead of '/'. -// If `src` contains invalid characters, `dest` is cleared and returns `false`. + +// WebSafeBase64Unescape() +// +// Converts a `src` string encoded in Base64 to its binary equivalent, writing +// it to a `dest` buffer, but using '-' instead of '+', and '_' instead of '/'. +// If `src` contains invalid characters, `dest` is cleared and returns `false`. bool WebSafeBase64Unescape(y_absl::string_view src, TString* dest); - -// Base64Escape() -// -// Encodes a `src` string into a base64-encoded string, with padding characters. -// This function conforms with RFC 4648 section 4 (base64). + +// Base64Escape() +// +// Encodes a `src` string into a base64-encoded string, with padding characters. +// This function conforms with RFC 4648 section 4 (base64). void Base64Escape(y_absl::string_view src, TString* dest); TString Base64Escape(y_absl::string_view src); - -// WebSafeBase64Escape() -// -// Encodes a `src` string into a base64-like string, using '-' instead of '+' -// and '_' instead of '/', and without padding. This function conforms with RFC -// 4648 section 5 (base64url). + +// WebSafeBase64Escape() +// +// Encodes a `src` string into a base64-like string, using '-' instead of '+' +// and '_' instead of '/', and without padding. This function conforms with RFC +// 4648 section 5 (base64url). void WebSafeBase64Escape(y_absl::string_view src, TString* dest); TString WebSafeBase64Escape(y_absl::string_view src); - -// HexStringToBytes() -// -// Converts an ASCII hex string into bytes, returning binary data of length -// `from.size()/2`. + +// HexStringToBytes() +// +// Converts an ASCII hex string into bytes, returning binary data of length +// `from.size()/2`. TString HexStringToBytes(y_absl::string_view from); - -// BytesToHexString() -// -// Converts binary data into an ASCII text string, returning a string of size -// `2*from.size()`. + +// BytesToHexString() +// +// Converts binary data into an ASCII text string, returning a string of size +// `2*from.size()`. TString BytesToHexString(y_absl::string_view from); - + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_ESCAPING_H_ + +#endif // ABSL_STRINGS_ESCAPING_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make index 4e57fc75f6..e3a7b28f61 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make @@ -1,16 +1,16 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() OWNER( somov g:cpp-contrib ) - -LICENSE(Apache-2.0) - + +LICENSE(Apache-2.0) + PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging @@ -21,15 +21,15 @@ PEERDIR( ADDINCL( GLOBAL contrib/restricted/abseil-cpp-tstring ) - -NO_COMPILER_WARNINGS() - + +NO_COMPILER_WARNINGS() + SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal) -SRCS( +SRCS( escaping.cc - ostringstream.cc - utf8.cc -) - -END() + ostringstream.cc + utf8.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h index 25428e304c..ba054e4646 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h @@ -1,156 +1,156 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Character Map Class -// -// A fast, bit-vector map for 8-bit unsigned characters. -// This class is useful for non-character purposes as well. - -#ifndef ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ -#define ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ - -#include <cstddef> -#include <cstdint> -#include <cstring> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Character Map Class +// +// A fast, bit-vector map for 8-bit unsigned characters. +// This class is useful for non-character purposes as well. + +#ifndef ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ +#define ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ + +#include <cstddef> +#include <cstdint> +#include <cstring> + #include "y_absl/base/macros.h" #include "y_absl/base/port.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -class Charmap { - public: - constexpr Charmap() : m_() {} - - // Initializes with a given char*. Note that NUL is not treated as - // a terminator, but rather a char to be flicked. - Charmap(const char* str, int len) : m_() { - while (len--) SetChar(*str++); - } - - // Initializes with a given char*. NUL is treated as a terminator - // and will not be in the charmap. - explicit Charmap(const char* str) : m_() { - while (*str) SetChar(*str++); - } - - constexpr bool contains(unsigned char c) const { - return (m_[c / 64] >> (c % 64)) & 0x1; - } - - // Returns true if and only if a character exists in both maps. - bool IntersectsWith(const Charmap& c) const { - for (size_t i = 0; i < ABSL_ARRAYSIZE(m_); ++i) { - if ((m_[i] & c.m_[i]) != 0) return true; - } - return false; - } - - bool IsZero() const { - for (uint64_t c : m_) { - if (c != 0) return false; - } - return true; - } - - // Containing only a single specified char. - static constexpr Charmap Char(char x) { - return Charmap(CharMaskForWord(x, 0), CharMaskForWord(x, 1), - CharMaskForWord(x, 2), CharMaskForWord(x, 3)); - } - +namespace strings_internal { + +class Charmap { + public: + constexpr Charmap() : m_() {} + + // Initializes with a given char*. Note that NUL is not treated as + // a terminator, but rather a char to be flicked. + Charmap(const char* str, int len) : m_() { + while (len--) SetChar(*str++); + } + + // Initializes with a given char*. NUL is treated as a terminator + // and will not be in the charmap. + explicit Charmap(const char* str) : m_() { + while (*str) SetChar(*str++); + } + + constexpr bool contains(unsigned char c) const { + return (m_[c / 64] >> (c % 64)) & 0x1; + } + + // Returns true if and only if a character exists in both maps. + bool IntersectsWith(const Charmap& c) const { + for (size_t i = 0; i < ABSL_ARRAYSIZE(m_); ++i) { + if ((m_[i] & c.m_[i]) != 0) return true; + } + return false; + } + + bool IsZero() const { + for (uint64_t c : m_) { + if (c != 0) return false; + } + return true; + } + + // Containing only a single specified char. + static constexpr Charmap Char(char x) { + return Charmap(CharMaskForWord(x, 0), CharMaskForWord(x, 1), + CharMaskForWord(x, 2), CharMaskForWord(x, 3)); + } + // Containing all the chars in the C-string 's'. - // Note that this is expensively recursive because of the C++11 constexpr - // formulation. Use only in constexpr initializers. - static constexpr Charmap FromString(const char* s) { - return *s == 0 ? Charmap() : (Char(*s) | FromString(s + 1)); - } - - // Containing all the chars in the closed interval [lo,hi]. - static constexpr Charmap Range(char lo, char hi) { - return Charmap(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1), - RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3)); - } - - friend constexpr Charmap operator&(const Charmap& a, const Charmap& b) { - return Charmap(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], a.m_[2] & b.m_[2], - a.m_[3] & b.m_[3]); - } - - friend constexpr Charmap operator|(const Charmap& a, const Charmap& b) { - return Charmap(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], a.m_[2] | b.m_[2], - a.m_[3] | b.m_[3]); - } - - friend constexpr Charmap operator~(const Charmap& a) { - return Charmap(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]); - } - - private: - constexpr Charmap(uint64_t b0, uint64_t b1, uint64_t b2, uint64_t b3) - : m_{b0, b1, b2, b3} {} - - static constexpr uint64_t RangeForWord(unsigned char lo, unsigned char hi, - uint64_t word) { - return OpenRangeFromZeroForWord(hi + 1, word) & - ~OpenRangeFromZeroForWord(lo, word); - } - - // All the chars in the specified word of the range [0, upper). - static constexpr uint64_t OpenRangeFromZeroForWord(uint64_t upper, - uint64_t word) { - return (upper <= 64 * word) - ? 0 - : (upper >= 64 * (word + 1)) - ? ~static_cast<uint64_t>(0) - : (~static_cast<uint64_t>(0) >> (64 - upper % 64)); - } - - static constexpr uint64_t CharMaskForWord(unsigned char x, uint64_t word) { - return (x / 64 == word) ? (static_cast<uint64_t>(1) << (x % 64)) : 0; - } - - private: - void SetChar(unsigned char c) { - m_[c / 64] |= static_cast<uint64_t>(1) << (c % 64); - } - - uint64_t m_[4]; -}; - -// Mirror the char-classifying predicates in <cctype> -constexpr Charmap UpperCharmap() { return Charmap::Range('A', 'Z'); } -constexpr Charmap LowerCharmap() { return Charmap::Range('a', 'z'); } -constexpr Charmap DigitCharmap() { return Charmap::Range('0', '9'); } -constexpr Charmap AlphaCharmap() { return LowerCharmap() | UpperCharmap(); } -constexpr Charmap AlnumCharmap() { return DigitCharmap() | AlphaCharmap(); } -constexpr Charmap XDigitCharmap() { - return DigitCharmap() | Charmap::Range('A', 'F') | Charmap::Range('a', 'f'); -} -constexpr Charmap PrintCharmap() { return Charmap::Range(0x20, 0x7e); } -constexpr Charmap SpaceCharmap() { return Charmap::FromString("\t\n\v\f\r "); } -constexpr Charmap CntrlCharmap() { - return Charmap::Range(0, 0x7f) & ~PrintCharmap(); -} -constexpr Charmap BlankCharmap() { return Charmap::FromString("\t "); } -constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); } -constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); } - -} // namespace strings_internal + // Note that this is expensively recursive because of the C++11 constexpr + // formulation. Use only in constexpr initializers. + static constexpr Charmap FromString(const char* s) { + return *s == 0 ? Charmap() : (Char(*s) | FromString(s + 1)); + } + + // Containing all the chars in the closed interval [lo,hi]. + static constexpr Charmap Range(char lo, char hi) { + return Charmap(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1), + RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3)); + } + + friend constexpr Charmap operator&(const Charmap& a, const Charmap& b) { + return Charmap(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], a.m_[2] & b.m_[2], + a.m_[3] & b.m_[3]); + } + + friend constexpr Charmap operator|(const Charmap& a, const Charmap& b) { + return Charmap(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], a.m_[2] | b.m_[2], + a.m_[3] | b.m_[3]); + } + + friend constexpr Charmap operator~(const Charmap& a) { + return Charmap(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]); + } + + private: + constexpr Charmap(uint64_t b0, uint64_t b1, uint64_t b2, uint64_t b3) + : m_{b0, b1, b2, b3} {} + + static constexpr uint64_t RangeForWord(unsigned char lo, unsigned char hi, + uint64_t word) { + return OpenRangeFromZeroForWord(hi + 1, word) & + ~OpenRangeFromZeroForWord(lo, word); + } + + // All the chars in the specified word of the range [0, upper). + static constexpr uint64_t OpenRangeFromZeroForWord(uint64_t upper, + uint64_t word) { + return (upper <= 64 * word) + ? 0 + : (upper >= 64 * (word + 1)) + ? ~static_cast<uint64_t>(0) + : (~static_cast<uint64_t>(0) >> (64 - upper % 64)); + } + + static constexpr uint64_t CharMaskForWord(unsigned char x, uint64_t word) { + return (x / 64 == word) ? (static_cast<uint64_t>(1) << (x % 64)) : 0; + } + + private: + void SetChar(unsigned char c) { + m_[c / 64] |= static_cast<uint64_t>(1) << (c % 64); + } + + uint64_t m_[4]; +}; + +// Mirror the char-classifying predicates in <cctype> +constexpr Charmap UpperCharmap() { return Charmap::Range('A', 'Z'); } +constexpr Charmap LowerCharmap() { return Charmap::Range('a', 'z'); } +constexpr Charmap DigitCharmap() { return Charmap::Range('0', '9'); } +constexpr Charmap AlphaCharmap() { return LowerCharmap() | UpperCharmap(); } +constexpr Charmap AlnumCharmap() { return DigitCharmap() | AlphaCharmap(); } +constexpr Charmap XDigitCharmap() { + return DigitCharmap() | Charmap::Range('A', 'F') | Charmap::Range('a', 'f'); +} +constexpr Charmap PrintCharmap() { return Charmap::Range(0x20, 0x7e); } +constexpr Charmap SpaceCharmap() { return Charmap::FromString("\t\n\v\f\r "); } +constexpr Charmap CntrlCharmap() { + return Charmap::Range(0, 0x7f) & ~PrintCharmap(); +} +constexpr Charmap BlankCharmap() { return Charmap::FromString("\t "); } +constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); } +constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); } + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ + +#endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc index 72a4fa188b..b8646c3194 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc @@ -1,359 +1,359 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/charconv_bigint.h" - -#include <algorithm> -#include <cassert> + +#include <algorithm> +#include <cassert> #include <util/generic/string.h> - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -namespace { - -// Table containing some large powers of 5, for fast computation. - -// Constant step size for entries in the kLargePowersOfFive table. Each entry -// is larger than the previous entry by a factor of 5**kLargePowerOfFiveStep -// (or 5**27). -// -// In other words, the Nth entry in the table is 5**(27*N). -// -// 5**27 is the largest power of 5 that fits in 64 bits. -constexpr int kLargePowerOfFiveStep = 27; - -// The largest legal index into the kLargePowersOfFive table. -// -// In other words, the largest precomputed power of 5 is 5**(27*20). -constexpr int kLargestPowerOfFiveIndex = 20; - -// Table of powers of (5**27), up to (5**27)**20 == 5**540. -// -// Used to generate large powers of 5 while limiting the number of repeated -// multiplications required. -// -// clang-format off -const uint32_t kLargePowersOfFive[] = { -// 5**27 (i=1), start=0, end=2 - 0xfa10079dU, 0x6765c793U, -// 5**54 (i=2), start=2, end=6 - 0x97d9f649U, 0x6664242dU, 0x29939b14U, 0x29c30f10U, -// 5**81 (i=3), start=6, end=12 - 0xc4f809c5U, 0x7bf3f22aU, 0x67bdae34U, 0xad340517U, 0x369d1b5fU, 0x10de1593U, -// 5**108 (i=4), start=12, end=20 - 0x92b260d1U, 0x9efff7c7U, 0x81de0ec6U, 0xaeba5d56U, 0x410664a4U, 0x4f40737aU, - 0x20d3846fU, 0x06d00f73U, -// 5**135 (i=5), start=20, end=30 - 0xff1b172dU, 0x13a1d71cU, 0xefa07617U, 0x7f682d3dU, 0xff8c90c0U, 0x3f0131e7U, - 0x3fdcb9feU, 0x917b0177U, 0x16c407a7U, 0x02c06b9dU, -// 5**162 (i=6), start=30, end=42 - 0x960f7199U, 0x056667ecU, 0xe07aefd8U, 0x80f2b9ccU, 0x8273f5e3U, 0xeb9a214aU, - 0x40b38005U, 0x0e477ad4U, 0x277d08e6U, 0xfa28b11eU, 0xd3f7d784U, 0x011c835bU, -// 5**189 (i=7), start=42, end=56 - 0xf723d9d5U, 0x3282d3f3U, 0xe00857d1U, 0x69659d25U, 0x2cf117cfU, 0x24da6d07U, - 0x954d1417U, 0x3e5d8cedU, 0x7a8bb766U, 0xfd785ae6U, 0x645436d2U, 0x40c78b34U, - 0x94151217U, 0x0072e9f7U, -// 5**216 (i=8), start=56, end=72 - 0x2b416aa1U, 0x7893c5a7U, 0xe37dc6d4U, 0x2bad2beaU, 0xf0fc846cU, 0x7575ae4bU, - 0x62587b14U, 0x83b67a34U, 0x02110cdbU, 0xf7992f55U, 0x00deb022U, 0xa4a23becU, - 0x8af5c5cdU, 0xb85b654fU, 0x818df38bU, 0x002e69d2U, -// 5**243 (i=9), start=72, end=90 - 0x3518cbbdU, 0x20b0c15fU, 0x38756c2fU, 0xfb5dc3ddU, 0x22ad2d94U, 0xbf35a952U, - 0xa699192aU, 0x9a613326U, 0xad2a9cedU, 0xd7f48968U, 0xe87dfb54U, 0xc8f05db6U, - 0x5ef67531U, 0x31c1ab49U, 0xe202ac9fU, 0x9b2957b5U, 0xa143f6d3U, 0x0012bf07U, -// 5**270 (i=10), start=90, end=110 - 0x8b971de9U, 0x21aba2e1U, 0x63944362U, 0x57172336U, 0xd9544225U, 0xfb534166U, - 0x08c563eeU, 0x14640ee2U, 0x24e40d31U, 0x02b06537U, 0x03887f14U, 0x0285e533U, - 0xb744ef26U, 0x8be3a6c4U, 0x266979b4U, 0x6761ece2U, 0xd9cb39e4U, 0xe67de319U, - 0x0d39e796U, 0x00079250U, -// 5**297 (i=11), start=110, end=132 - 0x260eb6e5U, 0xf414a796U, 0xee1a7491U, 0xdb9368ebU, 0xf50c105bU, 0x59157750U, - 0x9ed2fb5cU, 0xf6e56d8bU, 0xeaee8d23U, 0x0f319f75U, 0x2aa134d6U, 0xac2908e9U, - 0xd4413298U, 0x02f02a55U, 0x989d5a7aU, 0x70dde184U, 0xba8040a7U, 0x03200981U, - 0xbe03b11cU, 0x3c1c2a18U, 0xd60427a1U, 0x00030ee0U, -// 5**324 (i=12), start=132, end=156 - 0xce566d71U, 0xf1c4aa25U, 0x4e93ca53U, 0xa72283d0U, 0x551a73eaU, 0x3d0538e2U, - 0x8da4303fU, 0x6a58de60U, 0x0e660221U, 0x49cf61a6U, 0x8d058fc1U, 0xb9d1a14cU, - 0x4bab157dU, 0xc85c6932U, 0x518c8b9eU, 0x9b92b8d0U, 0x0d8a0e21U, 0xbd855df9U, - 0xb3ea59a1U, 0x8da29289U, 0x4584d506U, 0x3752d80fU, 0xb72569c6U, 0x00013c33U, -// 5**351 (i=13), start=156, end=182 - 0x190f354dU, 0x83695cfeU, 0xe5a4d0c7U, 0xb60fb7e8U, 0xee5bbcc4U, 0xb922054cU, - 0xbb4f0d85U, 0x48394028U, 0x1d8957dbU, 0x0d7edb14U, 0x4ecc7587U, 0x505e9e02U, - 0x4c87f36bU, 0x99e66bd6U, 0x44b9ed35U, 0x753037d4U, 0xe5fe5f27U, 0x2742c203U, - 0x13b2ed2bU, 0xdc525d2cU, 0xe6fde59aU, 0x77ffb18fU, 0x13c5752cU, 0x08a84bccU, - 0x859a4940U, 0x00007fb6U, -// 5**378 (i=14), start=182, end=210 - 0x4f98cb39U, 0xa60edbbcU, 0x83b5872eU, 0xa501acffU, 0x9cc76f78U, 0xbadd4c73U, - 0x43e989faU, 0xca7acf80U, 0x2e0c824fU, 0xb19f4ffcU, 0x092fd81cU, 0xe4eb645bU, - 0xa1ff84c2U, 0x8a5a83baU, 0xa8a1fae9U, 0x1db43609U, 0xb0fed50bU, 0x0dd7d2bdU, - 0x7d7accd8U, 0x91fa640fU, 0x37dcc6c5U, 0x1c417fd5U, 0xe4d462adU, 0xe8a43399U, - 0x131bf9a5U, 0x8df54d29U, 0x36547dc1U, 0x00003395U, -// 5**405 (i=15), start=210, end=240 - 0x5bd330f5U, 0x77d21967U, 0x1ac481b7U, 0x6be2f7ceU, 0x7f4792a9U, 0xe84c2c52U, - 0x84592228U, 0x9dcaf829U, 0xdab44ce1U, 0x3d0c311bU, 0x532e297dU, 0x4704e8b4U, - 0x9cdc32beU, 0x41e64d9dU, 0x7717bea1U, 0xa824c00dU, 0x08f50b27U, 0x0f198d77U, - 0x49bbfdf0U, 0x025c6c69U, 0xd4e55cd3U, 0xf083602bU, 0xb9f0fecdU, 0xc0864aeaU, - 0x9cb98681U, 0xaaf620e9U, 0xacb6df30U, 0x4faafe66U, 0x8af13c3bU, 0x000014d5U, -// 5**432 (i=16), start=240, end=272 - 0x682bb941U, 0x89a9f297U, 0xcba75d7bU, 0x404217b1U, 0xb4e519e9U, 0xa1bc162bU, - 0xf7f5910aU, 0x98715af5U, 0x2ff53e57U, 0xe3ef118cU, 0x490c4543U, 0xbc9b1734U, - 0x2affbe4dU, 0x4cedcb4cU, 0xfb14e99eU, 0x35e34212U, 0xece39c24U, 0x07673ab3U, - 0xe73115ddU, 0xd15d38e7U, 0x093eed3bU, 0xf8e7eac5U, 0x78a8cc80U, 0x25227aacU, - 0x3f590551U, 0x413da1cbU, 0xdf643a55U, 0xab65ad44U, 0xd70b23d7U, 0xc672cd76U, - 0x3364ea62U, 0x0000086aU, -// 5**459 (i=17), start=272, end=306 - 0x22f163ddU, 0x23cf07acU, 0xbe2af6c2U, 0xf412f6f6U, 0xc3ff541eU, 0x6eeaf7deU, - 0xa47047e0U, 0x408cda92U, 0x0f0eeb08U, 0x56deba9dU, 0xcfc6b090U, 0x8bbbdf04U, - 0x3933cdb3U, 0x9e7bb67dU, 0x9f297035U, 0x38946244U, 0xee1d37bbU, 0xde898174U, - 0x63f3559dU, 0x705b72fbU, 0x138d27d9U, 0xf8603a78U, 0x735eec44U, 0xe30987d5U, - 0xc6d38070U, 0x9cfe548eU, 0x9ff01422U, 0x7c564aa8U, 0x91cc60baU, 0xcbc3565dU, - 0x7550a50bU, 0x6909aeadU, 0x13234c45U, 0x00000366U, -// 5**486 (i=18), start=306, end=342 - 0x17954989U, 0x3a7d7709U, 0x98042de5U, 0xa9011443U, 0x45e723c2U, 0x269ffd6fU, - 0x58852a46U, 0xaaa1042aU, 0x2eee8153U, 0xb2b6c39eU, 0xaf845b65U, 0xf6c365d7U, - 0xe4cffb2bU, 0xc840e90cU, 0xabea8abbU, 0x5c58f8d2U, 0x5c19fa3aU, 0x4670910aU, - 0x4449f21cU, 0xefa645b3U, 0xcc427decU, 0x083c3d73U, 0x467cb413U, 0x6fe10ae4U, - 0x3caffc72U, 0x9f8da55eU, 0x5e5c8ea7U, 0x490594bbU, 0xf0871b0bU, 0xdd89816cU, - 0x8e931df8U, 0xe85ce1c9U, 0xcca090a5U, 0x575fa16bU, 0x6b9f106cU, 0x0000015fU, -// 5**513 (i=19), start=342, end=380 - 0xee20d805U, 0x57bc3c07U, 0xcdea624eU, 0xd3f0f52dU, 0x9924b4f4U, 0xcf968640U, - 0x61d41962U, 0xe87fb464U, 0xeaaf51c7U, 0x564c8b60U, 0xccda4028U, 0x529428bbU, - 0x313a1fa8U, 0x96bd0f94U, 0x7a82ebaaU, 0xad99e7e9U, 0xf2668cd4U, 0xbe33a45eU, - 0xfd0db669U, 0x87ee369fU, 0xd3ec20edU, 0x9c4d7db7U, 0xdedcf0d8U, 0x7cd2ca64U, - 0xe25a6577U, 0x61003fd4U, 0xe56f54ccU, 0x10b7c748U, 0x40526e5eU, 0x7300ae87U, - 0x5c439261U, 0x2c0ff469U, 0xbf723f12U, 0xb2379b61U, 0xbf59b4f5U, 0xc91b1c3fU, - 0xf0046d27U, 0x0000008dU, -// 5**540 (i=20), start=380, end=420 - 0x525c9e11U, 0xf4e0eb41U, 0xebb2895dU, 0x5da512f9U, 0x7d9b29d4U, 0x452f4edcU, - 0x0b90bc37U, 0x341777cbU, 0x63d269afU, 0x1da77929U, 0x0a5c1826U, 0x77991898U, - 0x5aeddf86U, 0xf853a877U, 0x538c31ccU, 0xe84896daU, 0xb7a0010bU, 0x17ef4de5U, - 0xa52a2adeU, 0x029fd81cU, 0x987ce701U, 0x27fefd77U, 0xdb46c66fU, 0x5d301900U, - 0x496998c0U, 0xbb6598b9U, 0x5eebb607U, 0xe547354aU, 0xdf4a2f7eU, 0xf06c4955U, - 0x96242ffaU, 0x1775fb27U, 0xbecc58ceU, 0xebf2a53bU, 0x3eaad82aU, 0xf41137baU, - 0x573e6fbaU, 0xfb4866b8U, 0x54002148U, 0x00000039U, -}; -// clang-format on - -// Returns a pointer to the big integer data for (5**27)**i. i must be -// between 1 and 20, inclusive. -const uint32_t* LargePowerOfFiveData(int i) { - return kLargePowersOfFive + i * (i - 1); -} - -// Returns the size of the big integer data for (5**27)**i, in words. i must be -// between 1 and 20, inclusive. -int LargePowerOfFiveSize(int i) { return 2 * i; } -} // namespace - +namespace strings_internal { + +namespace { + +// Table containing some large powers of 5, for fast computation. + +// Constant step size for entries in the kLargePowersOfFive table. Each entry +// is larger than the previous entry by a factor of 5**kLargePowerOfFiveStep +// (or 5**27). +// +// In other words, the Nth entry in the table is 5**(27*N). +// +// 5**27 is the largest power of 5 that fits in 64 bits. +constexpr int kLargePowerOfFiveStep = 27; + +// The largest legal index into the kLargePowersOfFive table. +// +// In other words, the largest precomputed power of 5 is 5**(27*20). +constexpr int kLargestPowerOfFiveIndex = 20; + +// Table of powers of (5**27), up to (5**27)**20 == 5**540. +// +// Used to generate large powers of 5 while limiting the number of repeated +// multiplications required. +// +// clang-format off +const uint32_t kLargePowersOfFive[] = { +// 5**27 (i=1), start=0, end=2 + 0xfa10079dU, 0x6765c793U, +// 5**54 (i=2), start=2, end=6 + 0x97d9f649U, 0x6664242dU, 0x29939b14U, 0x29c30f10U, +// 5**81 (i=3), start=6, end=12 + 0xc4f809c5U, 0x7bf3f22aU, 0x67bdae34U, 0xad340517U, 0x369d1b5fU, 0x10de1593U, +// 5**108 (i=4), start=12, end=20 + 0x92b260d1U, 0x9efff7c7U, 0x81de0ec6U, 0xaeba5d56U, 0x410664a4U, 0x4f40737aU, + 0x20d3846fU, 0x06d00f73U, +// 5**135 (i=5), start=20, end=30 + 0xff1b172dU, 0x13a1d71cU, 0xefa07617U, 0x7f682d3dU, 0xff8c90c0U, 0x3f0131e7U, + 0x3fdcb9feU, 0x917b0177U, 0x16c407a7U, 0x02c06b9dU, +// 5**162 (i=6), start=30, end=42 + 0x960f7199U, 0x056667ecU, 0xe07aefd8U, 0x80f2b9ccU, 0x8273f5e3U, 0xeb9a214aU, + 0x40b38005U, 0x0e477ad4U, 0x277d08e6U, 0xfa28b11eU, 0xd3f7d784U, 0x011c835bU, +// 5**189 (i=7), start=42, end=56 + 0xf723d9d5U, 0x3282d3f3U, 0xe00857d1U, 0x69659d25U, 0x2cf117cfU, 0x24da6d07U, + 0x954d1417U, 0x3e5d8cedU, 0x7a8bb766U, 0xfd785ae6U, 0x645436d2U, 0x40c78b34U, + 0x94151217U, 0x0072e9f7U, +// 5**216 (i=8), start=56, end=72 + 0x2b416aa1U, 0x7893c5a7U, 0xe37dc6d4U, 0x2bad2beaU, 0xf0fc846cU, 0x7575ae4bU, + 0x62587b14U, 0x83b67a34U, 0x02110cdbU, 0xf7992f55U, 0x00deb022U, 0xa4a23becU, + 0x8af5c5cdU, 0xb85b654fU, 0x818df38bU, 0x002e69d2U, +// 5**243 (i=9), start=72, end=90 + 0x3518cbbdU, 0x20b0c15fU, 0x38756c2fU, 0xfb5dc3ddU, 0x22ad2d94U, 0xbf35a952U, + 0xa699192aU, 0x9a613326U, 0xad2a9cedU, 0xd7f48968U, 0xe87dfb54U, 0xc8f05db6U, + 0x5ef67531U, 0x31c1ab49U, 0xe202ac9fU, 0x9b2957b5U, 0xa143f6d3U, 0x0012bf07U, +// 5**270 (i=10), start=90, end=110 + 0x8b971de9U, 0x21aba2e1U, 0x63944362U, 0x57172336U, 0xd9544225U, 0xfb534166U, + 0x08c563eeU, 0x14640ee2U, 0x24e40d31U, 0x02b06537U, 0x03887f14U, 0x0285e533U, + 0xb744ef26U, 0x8be3a6c4U, 0x266979b4U, 0x6761ece2U, 0xd9cb39e4U, 0xe67de319U, + 0x0d39e796U, 0x00079250U, +// 5**297 (i=11), start=110, end=132 + 0x260eb6e5U, 0xf414a796U, 0xee1a7491U, 0xdb9368ebU, 0xf50c105bU, 0x59157750U, + 0x9ed2fb5cU, 0xf6e56d8bU, 0xeaee8d23U, 0x0f319f75U, 0x2aa134d6U, 0xac2908e9U, + 0xd4413298U, 0x02f02a55U, 0x989d5a7aU, 0x70dde184U, 0xba8040a7U, 0x03200981U, + 0xbe03b11cU, 0x3c1c2a18U, 0xd60427a1U, 0x00030ee0U, +// 5**324 (i=12), start=132, end=156 + 0xce566d71U, 0xf1c4aa25U, 0x4e93ca53U, 0xa72283d0U, 0x551a73eaU, 0x3d0538e2U, + 0x8da4303fU, 0x6a58de60U, 0x0e660221U, 0x49cf61a6U, 0x8d058fc1U, 0xb9d1a14cU, + 0x4bab157dU, 0xc85c6932U, 0x518c8b9eU, 0x9b92b8d0U, 0x0d8a0e21U, 0xbd855df9U, + 0xb3ea59a1U, 0x8da29289U, 0x4584d506U, 0x3752d80fU, 0xb72569c6U, 0x00013c33U, +// 5**351 (i=13), start=156, end=182 + 0x190f354dU, 0x83695cfeU, 0xe5a4d0c7U, 0xb60fb7e8U, 0xee5bbcc4U, 0xb922054cU, + 0xbb4f0d85U, 0x48394028U, 0x1d8957dbU, 0x0d7edb14U, 0x4ecc7587U, 0x505e9e02U, + 0x4c87f36bU, 0x99e66bd6U, 0x44b9ed35U, 0x753037d4U, 0xe5fe5f27U, 0x2742c203U, + 0x13b2ed2bU, 0xdc525d2cU, 0xe6fde59aU, 0x77ffb18fU, 0x13c5752cU, 0x08a84bccU, + 0x859a4940U, 0x00007fb6U, +// 5**378 (i=14), start=182, end=210 + 0x4f98cb39U, 0xa60edbbcU, 0x83b5872eU, 0xa501acffU, 0x9cc76f78U, 0xbadd4c73U, + 0x43e989faU, 0xca7acf80U, 0x2e0c824fU, 0xb19f4ffcU, 0x092fd81cU, 0xe4eb645bU, + 0xa1ff84c2U, 0x8a5a83baU, 0xa8a1fae9U, 0x1db43609U, 0xb0fed50bU, 0x0dd7d2bdU, + 0x7d7accd8U, 0x91fa640fU, 0x37dcc6c5U, 0x1c417fd5U, 0xe4d462adU, 0xe8a43399U, + 0x131bf9a5U, 0x8df54d29U, 0x36547dc1U, 0x00003395U, +// 5**405 (i=15), start=210, end=240 + 0x5bd330f5U, 0x77d21967U, 0x1ac481b7U, 0x6be2f7ceU, 0x7f4792a9U, 0xe84c2c52U, + 0x84592228U, 0x9dcaf829U, 0xdab44ce1U, 0x3d0c311bU, 0x532e297dU, 0x4704e8b4U, + 0x9cdc32beU, 0x41e64d9dU, 0x7717bea1U, 0xa824c00dU, 0x08f50b27U, 0x0f198d77U, + 0x49bbfdf0U, 0x025c6c69U, 0xd4e55cd3U, 0xf083602bU, 0xb9f0fecdU, 0xc0864aeaU, + 0x9cb98681U, 0xaaf620e9U, 0xacb6df30U, 0x4faafe66U, 0x8af13c3bU, 0x000014d5U, +// 5**432 (i=16), start=240, end=272 + 0x682bb941U, 0x89a9f297U, 0xcba75d7bU, 0x404217b1U, 0xb4e519e9U, 0xa1bc162bU, + 0xf7f5910aU, 0x98715af5U, 0x2ff53e57U, 0xe3ef118cU, 0x490c4543U, 0xbc9b1734U, + 0x2affbe4dU, 0x4cedcb4cU, 0xfb14e99eU, 0x35e34212U, 0xece39c24U, 0x07673ab3U, + 0xe73115ddU, 0xd15d38e7U, 0x093eed3bU, 0xf8e7eac5U, 0x78a8cc80U, 0x25227aacU, + 0x3f590551U, 0x413da1cbU, 0xdf643a55U, 0xab65ad44U, 0xd70b23d7U, 0xc672cd76U, + 0x3364ea62U, 0x0000086aU, +// 5**459 (i=17), start=272, end=306 + 0x22f163ddU, 0x23cf07acU, 0xbe2af6c2U, 0xf412f6f6U, 0xc3ff541eU, 0x6eeaf7deU, + 0xa47047e0U, 0x408cda92U, 0x0f0eeb08U, 0x56deba9dU, 0xcfc6b090U, 0x8bbbdf04U, + 0x3933cdb3U, 0x9e7bb67dU, 0x9f297035U, 0x38946244U, 0xee1d37bbU, 0xde898174U, + 0x63f3559dU, 0x705b72fbU, 0x138d27d9U, 0xf8603a78U, 0x735eec44U, 0xe30987d5U, + 0xc6d38070U, 0x9cfe548eU, 0x9ff01422U, 0x7c564aa8U, 0x91cc60baU, 0xcbc3565dU, + 0x7550a50bU, 0x6909aeadU, 0x13234c45U, 0x00000366U, +// 5**486 (i=18), start=306, end=342 + 0x17954989U, 0x3a7d7709U, 0x98042de5U, 0xa9011443U, 0x45e723c2U, 0x269ffd6fU, + 0x58852a46U, 0xaaa1042aU, 0x2eee8153U, 0xb2b6c39eU, 0xaf845b65U, 0xf6c365d7U, + 0xe4cffb2bU, 0xc840e90cU, 0xabea8abbU, 0x5c58f8d2U, 0x5c19fa3aU, 0x4670910aU, + 0x4449f21cU, 0xefa645b3U, 0xcc427decU, 0x083c3d73U, 0x467cb413U, 0x6fe10ae4U, + 0x3caffc72U, 0x9f8da55eU, 0x5e5c8ea7U, 0x490594bbU, 0xf0871b0bU, 0xdd89816cU, + 0x8e931df8U, 0xe85ce1c9U, 0xcca090a5U, 0x575fa16bU, 0x6b9f106cU, 0x0000015fU, +// 5**513 (i=19), start=342, end=380 + 0xee20d805U, 0x57bc3c07U, 0xcdea624eU, 0xd3f0f52dU, 0x9924b4f4U, 0xcf968640U, + 0x61d41962U, 0xe87fb464U, 0xeaaf51c7U, 0x564c8b60U, 0xccda4028U, 0x529428bbU, + 0x313a1fa8U, 0x96bd0f94U, 0x7a82ebaaU, 0xad99e7e9U, 0xf2668cd4U, 0xbe33a45eU, + 0xfd0db669U, 0x87ee369fU, 0xd3ec20edU, 0x9c4d7db7U, 0xdedcf0d8U, 0x7cd2ca64U, + 0xe25a6577U, 0x61003fd4U, 0xe56f54ccU, 0x10b7c748U, 0x40526e5eU, 0x7300ae87U, + 0x5c439261U, 0x2c0ff469U, 0xbf723f12U, 0xb2379b61U, 0xbf59b4f5U, 0xc91b1c3fU, + 0xf0046d27U, 0x0000008dU, +// 5**540 (i=20), start=380, end=420 + 0x525c9e11U, 0xf4e0eb41U, 0xebb2895dU, 0x5da512f9U, 0x7d9b29d4U, 0x452f4edcU, + 0x0b90bc37U, 0x341777cbU, 0x63d269afU, 0x1da77929U, 0x0a5c1826U, 0x77991898U, + 0x5aeddf86U, 0xf853a877U, 0x538c31ccU, 0xe84896daU, 0xb7a0010bU, 0x17ef4de5U, + 0xa52a2adeU, 0x029fd81cU, 0x987ce701U, 0x27fefd77U, 0xdb46c66fU, 0x5d301900U, + 0x496998c0U, 0xbb6598b9U, 0x5eebb607U, 0xe547354aU, 0xdf4a2f7eU, 0xf06c4955U, + 0x96242ffaU, 0x1775fb27U, 0xbecc58ceU, 0xebf2a53bU, 0x3eaad82aU, 0xf41137baU, + 0x573e6fbaU, 0xfb4866b8U, 0x54002148U, 0x00000039U, +}; +// clang-format on + +// Returns a pointer to the big integer data for (5**27)**i. i must be +// between 1 and 20, inclusive. +const uint32_t* LargePowerOfFiveData(int i) { + return kLargePowersOfFive + i * (i - 1); +} + +// Returns the size of the big integer data for (5**27)**i, in words. i must be +// between 1 and 20, inclusive. +int LargePowerOfFiveSize(int i) { return 2 * i; } +} // namespace + ABSL_DLL const uint32_t kFiveToNth[14] = { - 1, 5, 25, 125, 625, 3125, 15625, - 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125, -}; - + 1, 5, 25, 125, 625, 3125, 15625, + 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125, +}; + ABSL_DLL const uint32_t kTenToNth[10] = { - 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, -}; - -template <int max_words> -int BigUnsigned<max_words>::ReadFloatMantissa(const ParsedFloat& fp, - int significant_digits) { - SetToZero(); - assert(fp.type == FloatType::kNumber); - - if (fp.subrange_begin == nullptr) { - // We already exactly parsed the mantissa, so no more work is necessary. - words_[0] = fp.mantissa & 0xffffffffu; - words_[1] = fp.mantissa >> 32; - if (words_[1]) { - size_ = 2; - } else if (words_[0]) { - size_ = 1; - } - return fp.exponent; - } - int exponent_adjust = - ReadDigits(fp.subrange_begin, fp.subrange_end, significant_digits); - return fp.literal_exponent + exponent_adjust; -} - -template <int max_words> -int BigUnsigned<max_words>::ReadDigits(const char* begin, const char* end, - int significant_digits) { - assert(significant_digits <= Digits10() + 1); - SetToZero(); - - bool after_decimal_point = false; - // Discard any leading zeroes before the decimal point - while (begin < end && *begin == '0') { - ++begin; - } - int dropped_digits = 0; - // Discard any trailing zeroes. These may or may not be after the decimal - // point. - while (begin < end && *std::prev(end) == '0') { - --end; - ++dropped_digits; - } - if (begin < end && *std::prev(end) == '.') { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, +}; + +template <int max_words> +int BigUnsigned<max_words>::ReadFloatMantissa(const ParsedFloat& fp, + int significant_digits) { + SetToZero(); + assert(fp.type == FloatType::kNumber); + + if (fp.subrange_begin == nullptr) { + // We already exactly parsed the mantissa, so no more work is necessary. + words_[0] = fp.mantissa & 0xffffffffu; + words_[1] = fp.mantissa >> 32; + if (words_[1]) { + size_ = 2; + } else if (words_[0]) { + size_ = 1; + } + return fp.exponent; + } + int exponent_adjust = + ReadDigits(fp.subrange_begin, fp.subrange_end, significant_digits); + return fp.literal_exponent + exponent_adjust; +} + +template <int max_words> +int BigUnsigned<max_words>::ReadDigits(const char* begin, const char* end, + int significant_digits) { + assert(significant_digits <= Digits10() + 1); + SetToZero(); + + bool after_decimal_point = false; + // Discard any leading zeroes before the decimal point + while (begin < end && *begin == '0') { + ++begin; + } + int dropped_digits = 0; + // Discard any trailing zeroes. These may or may not be after the decimal + // point. + while (begin < end && *std::prev(end) == '0') { + --end; + ++dropped_digits; + } + if (begin < end && *std::prev(end) == '.') { // If the string ends in '.', either before or after dropping zeroes, then - // drop the decimal point and look for more digits to drop. - dropped_digits = 0; - --end; - while (begin < end && *std::prev(end) == '0') { - --end; - ++dropped_digits; - } - } else if (dropped_digits) { - // We dropped digits, and aren't sure if they're before or after the decimal - // point. Figure that out now. - const char* dp = std::find(begin, end, '.'); - if (dp != end) { - // The dropped trailing digits were after the decimal point, so don't - // count them. - dropped_digits = 0; - } - } - // Any non-fraction digits we dropped need to be accounted for in our exponent - // adjustment. - int exponent_adjust = dropped_digits; - - uint32_t queued = 0; - int digits_queued = 0; - for (; begin != end && significant_digits > 0; ++begin) { - if (*begin == '.') { - after_decimal_point = true; - continue; - } - if (after_decimal_point) { - // For each fractional digit we emit in our parsed integer, adjust our - // decimal exponent to compensate. - --exponent_adjust; - } - int digit = (*begin - '0'); - --significant_digits; - if (significant_digits == 0 && std::next(begin) != end && - (digit == 0 || digit == 5)) { - // If this is the very last significant digit, but insignificant digits - // remain, we know that the last of those remaining significant digits is - // nonzero. (If it wasn't, we would have stripped it before we got here.) - // So if this final digit is a 0 or 5, adjust it upward by 1. - // - // This adjustment is what allows incredibly large mantissas ending in - // 500000...000000000001 to correctly round up, rather than to nearest. - ++digit; - } - queued = 10 * queued + digit; - ++digits_queued; - if (digits_queued == kMaxSmallPowerOfTen) { - MultiplyBy(kTenToNth[kMaxSmallPowerOfTen]); - AddWithCarry(0, queued); - queued = digits_queued = 0; - } - } - // Encode any remaining digits. - if (digits_queued) { - MultiplyBy(kTenToNth[digits_queued]); - AddWithCarry(0, queued); - } - - // If any insignificant digits remain, we will drop them. But if we have not - // yet read the decimal point, then we have to adjust the exponent to account - // for the dropped digits. - if (begin < end && !after_decimal_point) { - // This call to std::find will result in a pointer either to the decimal - // point, or to the end of our buffer if there was none. - // - // Either way, [begin, decimal_point) will contain the set of dropped digits - // that require an exponent adjustment. - const char* decimal_point = std::find(begin, end, '.'); - exponent_adjust += (decimal_point - begin); - } - return exponent_adjust; -} - -template <int max_words> -/* static */ BigUnsigned<max_words> BigUnsigned<max_words>::FiveToTheNth( - int n) { - BigUnsigned answer(1u); - - // Seed from the table of large powers, if possible. - bool first_pass = true; - while (n >= kLargePowerOfFiveStep) { - int big_power = - std::min(n / kLargePowerOfFiveStep, kLargestPowerOfFiveIndex); - if (first_pass) { - // just copy, rather than multiplying by 1 - std::copy( - LargePowerOfFiveData(big_power), - LargePowerOfFiveData(big_power) + LargePowerOfFiveSize(big_power), - answer.words_); - answer.size_ = LargePowerOfFiveSize(big_power); - first_pass = false; - } else { - answer.MultiplyBy(LargePowerOfFiveSize(big_power), - LargePowerOfFiveData(big_power)); - } - n -= kLargePowerOfFiveStep * big_power; - } - answer.MultiplyByFiveToTheNth(n); - return answer; -} - -template <int max_words> -void BigUnsigned<max_words>::MultiplyStep(int original_size, - const uint32_t* other_words, - int other_size, int step) { - int this_i = std::min(original_size - 1, step); - int other_i = step - this_i; - - uint64_t this_word = 0; - uint64_t carry = 0; - for (; this_i >= 0 && other_i < other_size; --this_i, ++other_i) { - uint64_t product = words_[this_i]; - product *= other_words[other_i]; - this_word += product; - carry += (this_word >> 32); - this_word &= 0xffffffff; - } - AddWithCarry(step + 1, carry); - words_[step] = this_word & 0xffffffff; - if (this_word > 0 && size_ <= step) { - size_ = step + 1; - } -} - -template <int max_words> + // drop the decimal point and look for more digits to drop. + dropped_digits = 0; + --end; + while (begin < end && *std::prev(end) == '0') { + --end; + ++dropped_digits; + } + } else if (dropped_digits) { + // We dropped digits, and aren't sure if they're before or after the decimal + // point. Figure that out now. + const char* dp = std::find(begin, end, '.'); + if (dp != end) { + // The dropped trailing digits were after the decimal point, so don't + // count them. + dropped_digits = 0; + } + } + // Any non-fraction digits we dropped need to be accounted for in our exponent + // adjustment. + int exponent_adjust = dropped_digits; + + uint32_t queued = 0; + int digits_queued = 0; + for (; begin != end && significant_digits > 0; ++begin) { + if (*begin == '.') { + after_decimal_point = true; + continue; + } + if (after_decimal_point) { + // For each fractional digit we emit in our parsed integer, adjust our + // decimal exponent to compensate. + --exponent_adjust; + } + int digit = (*begin - '0'); + --significant_digits; + if (significant_digits == 0 && std::next(begin) != end && + (digit == 0 || digit == 5)) { + // If this is the very last significant digit, but insignificant digits + // remain, we know that the last of those remaining significant digits is + // nonzero. (If it wasn't, we would have stripped it before we got here.) + // So if this final digit is a 0 or 5, adjust it upward by 1. + // + // This adjustment is what allows incredibly large mantissas ending in + // 500000...000000000001 to correctly round up, rather than to nearest. + ++digit; + } + queued = 10 * queued + digit; + ++digits_queued; + if (digits_queued == kMaxSmallPowerOfTen) { + MultiplyBy(kTenToNth[kMaxSmallPowerOfTen]); + AddWithCarry(0, queued); + queued = digits_queued = 0; + } + } + // Encode any remaining digits. + if (digits_queued) { + MultiplyBy(kTenToNth[digits_queued]); + AddWithCarry(0, queued); + } + + // If any insignificant digits remain, we will drop them. But if we have not + // yet read the decimal point, then we have to adjust the exponent to account + // for the dropped digits. + if (begin < end && !after_decimal_point) { + // This call to std::find will result in a pointer either to the decimal + // point, or to the end of our buffer if there was none. + // + // Either way, [begin, decimal_point) will contain the set of dropped digits + // that require an exponent adjustment. + const char* decimal_point = std::find(begin, end, '.'); + exponent_adjust += (decimal_point - begin); + } + return exponent_adjust; +} + +template <int max_words> +/* static */ BigUnsigned<max_words> BigUnsigned<max_words>::FiveToTheNth( + int n) { + BigUnsigned answer(1u); + + // Seed from the table of large powers, if possible. + bool first_pass = true; + while (n >= kLargePowerOfFiveStep) { + int big_power = + std::min(n / kLargePowerOfFiveStep, kLargestPowerOfFiveIndex); + if (first_pass) { + // just copy, rather than multiplying by 1 + std::copy( + LargePowerOfFiveData(big_power), + LargePowerOfFiveData(big_power) + LargePowerOfFiveSize(big_power), + answer.words_); + answer.size_ = LargePowerOfFiveSize(big_power); + first_pass = false; + } else { + answer.MultiplyBy(LargePowerOfFiveSize(big_power), + LargePowerOfFiveData(big_power)); + } + n -= kLargePowerOfFiveStep * big_power; + } + answer.MultiplyByFiveToTheNth(n); + return answer; +} + +template <int max_words> +void BigUnsigned<max_words>::MultiplyStep(int original_size, + const uint32_t* other_words, + int other_size, int step) { + int this_i = std::min(original_size - 1, step); + int other_i = step - this_i; + + uint64_t this_word = 0; + uint64_t carry = 0; + for (; this_i >= 0 && other_i < other_size; --this_i, ++other_i) { + uint64_t product = words_[this_i]; + product *= other_words[other_i]; + this_word += product; + carry += (this_word >> 32); + this_word &= 0xffffffff; + } + AddWithCarry(step + 1, carry); + words_[step] = this_word & 0xffffffff; + if (this_word > 0 && size_ <= step) { + size_ = step + 1; + } +} + +template <int max_words> TString BigUnsigned<max_words>::ToString() const { - BigUnsigned<max_words> copy = *this; + BigUnsigned<max_words> copy = *this; TString result; - // Build result in reverse order - while (copy.size() > 0) { - int next_digit = copy.DivMod<10>(); - result.push_back('0' + next_digit); - } - if (result.empty()) { - result.push_back('0'); - } + // Build result in reverse order + while (copy.size() > 0) { + int next_digit = copy.DivMod<10>(); + result.push_back('0' + next_digit); + } + if (result.empty()) { + result.push_back('0'); + } std::reverse(result.begin(), result.vend()); - return result; -} - -template class BigUnsigned<4>; -template class BigUnsigned<84>; - -} // namespace strings_internal + return result; +} + +template class BigUnsigned<4>; +template class BigUnsigned<84>; + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h index a77aab14dd..4508b8f24f 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h @@ -1,423 +1,423 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ -#define ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ - -#include <algorithm> -#include <cstdint> -#include <iostream> +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ +#define ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ + +#include <algorithm> +#include <cstdint> +#include <iostream> #include <util/generic/string.h> - + #include "y_absl/base/config.h" #include "y_absl/strings/ascii.h" #include "y_absl/strings/internal/charconv_parse.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -// The largest power that 5 that can be raised to, and still fit in a uint32_t. -constexpr int kMaxSmallPowerOfFive = 13; -// The largest power that 10 that can be raised to, and still fit in a uint32_t. -constexpr int kMaxSmallPowerOfTen = 9; - +namespace strings_internal { + +// The largest power that 5 that can be raised to, and still fit in a uint32_t. +constexpr int kMaxSmallPowerOfFive = 13; +// The largest power that 10 that can be raised to, and still fit in a uint32_t. +constexpr int kMaxSmallPowerOfTen = 9; + ABSL_DLL extern const uint32_t kFiveToNth[kMaxSmallPowerOfFive + 1]; ABSL_DLL extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1]; - -// Large, fixed-width unsigned integer. -// -// Exact rounding for decimal-to-binary floating point conversion requires very + +// Large, fixed-width unsigned integer. +// +// Exact rounding for decimal-to-binary floating point conversion requires very // large integer math, but a design goal of y_absl::from_chars is to avoid -// allocating memory. The integer precision needed for decimal-to-binary -// conversions is large but bounded, so a huge fixed-width integer class -// suffices. -// -// This is an intentionally limited big integer class. Only needed operations -// are implemented. All storage lives in an array data member, and all -// arithmetic is done in-place, to avoid requiring separate storage for operand -// and result. -// -// This is an internal class. Some methods live in the .cc file, and are -// instantiated only for the values of max_words we need. -template <int max_words> -class BigUnsigned { - public: - static_assert(max_words == 4 || max_words == 84, - "unsupported max_words value"); - - BigUnsigned() : size_(0), words_{} {} - explicit constexpr BigUnsigned(uint64_t v) - : size_((v >> 32) ? 2 : v ? 1 : 0), - words_{static_cast<uint32_t>(v & 0xffffffffu), - static_cast<uint32_t>(v >> 32)} {} - - // Constructs a BigUnsigned from the given string_view containing a decimal +// allocating memory. The integer precision needed for decimal-to-binary +// conversions is large but bounded, so a huge fixed-width integer class +// suffices. +// +// This is an intentionally limited big integer class. Only needed operations +// are implemented. All storage lives in an array data member, and all +// arithmetic is done in-place, to avoid requiring separate storage for operand +// and result. +// +// This is an internal class. Some methods live in the .cc file, and are +// instantiated only for the values of max_words we need. +template <int max_words> +class BigUnsigned { + public: + static_assert(max_words == 4 || max_words == 84, + "unsupported max_words value"); + + BigUnsigned() : size_(0), words_{} {} + explicit constexpr BigUnsigned(uint64_t v) + : size_((v >> 32) ? 2 : v ? 1 : 0), + words_{static_cast<uint32_t>(v & 0xffffffffu), + static_cast<uint32_t>(v >> 32)} {} + + // Constructs a BigUnsigned from the given string_view containing a decimal // value. If the input string is not a decimal integer, constructs a 0 - // instead. + // instead. explicit BigUnsigned(y_absl::string_view sv) : size_(0), words_{} { - // Check for valid input, returning a 0 otherwise. This is reasonable - // behavior only because this constructor is for unit tests. - if (std::find_if_not(sv.begin(), sv.end(), ascii_isdigit) != sv.end() || - sv.empty()) { - return; - } - int exponent_adjust = - ReadDigits(sv.data(), sv.data() + sv.size(), Digits10() + 1); - if (exponent_adjust > 0) { - MultiplyByTenToTheNth(exponent_adjust); - } - } - - // Loads the mantissa value of a previously-parsed float. - // - // Returns the associated decimal exponent. The value of the parsed float is - // exactly *this * 10**exponent. - int ReadFloatMantissa(const ParsedFloat& fp, int significant_digits); - - // Returns the number of decimal digits of precision this type provides. All - // numbers with this many decimal digits or fewer are representable by this - // type. - // - // Analagous to std::numeric_limits<BigUnsigned>::digits10. - static constexpr int Digits10() { - // 9975007/1035508 is very slightly less than log10(2**32). - return static_cast<uint64_t>(max_words) * 9975007 / 1035508; - } - - // Shifts left by the given number of bits. - void ShiftLeft(int count) { - if (count > 0) { - const int word_shift = count / 32; - if (word_shift >= max_words) { - SetToZero(); - return; - } - size_ = (std::min)(size_ + word_shift, max_words); - count %= 32; - if (count == 0) { - std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_); - } else { - for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) { - words_[i] = (words_[i - word_shift] << count) | - (words_[i - word_shift - 1] >> (32 - count)); - } - words_[word_shift] = words_[0] << count; - // Grow size_ if necessary. - if (size_ < max_words && words_[size_]) { - ++size_; - } - } - std::fill(words_, words_ + word_shift, 0u); - } - } - - - // Multiplies by v in-place. - void MultiplyBy(uint32_t v) { - if (size_ == 0 || v == 1) { - return; - } - if (v == 0) { - SetToZero(); - return; - } - const uint64_t factor = v; - uint64_t window = 0; - for (int i = 0; i < size_; ++i) { - window += factor * words_[i]; - words_[i] = window & 0xffffffff; - window >>= 32; - } - // If carry bits remain and there's space for them, grow size_. - if (window && size_ < max_words) { - words_[size_] = window & 0xffffffff; - ++size_; - } - } - - void MultiplyBy(uint64_t v) { - uint32_t words[2]; - words[0] = static_cast<uint32_t>(v); - words[1] = static_cast<uint32_t>(v >> 32); - if (words[1] == 0) { - MultiplyBy(words[0]); - } else { - MultiplyBy(2, words); - } - } - - // Multiplies in place by 5 to the power of n. n must be non-negative. - void MultiplyByFiveToTheNth(int n) { - while (n >= kMaxSmallPowerOfFive) { - MultiplyBy(kFiveToNth[kMaxSmallPowerOfFive]); - n -= kMaxSmallPowerOfFive; - } - if (n > 0) { - MultiplyBy(kFiveToNth[n]); - } - } - - // Multiplies in place by 10 to the power of n. n must be non-negative. - void MultiplyByTenToTheNth(int n) { - if (n > kMaxSmallPowerOfTen) { - // For large n, raise to a power of 5, then shift left by the same amount. - // (10**n == 5**n * 2**n.) This requires fewer multiplications overall. - MultiplyByFiveToTheNth(n); - ShiftLeft(n); - } else if (n > 0) { - // We can do this more quickly for very small N by using a single - // multiplication. - MultiplyBy(kTenToNth[n]); - } - } - - // Returns the value of 5**n, for non-negative n. This implementation uses - // a lookup table, and is faster then seeding a BigUnsigned with 1 and calling - // MultiplyByFiveToTheNth(). - static BigUnsigned FiveToTheNth(int n); - - // Multiplies by another BigUnsigned, in-place. - template <int M> - void MultiplyBy(const BigUnsigned<M>& other) { - MultiplyBy(other.size(), other.words()); - } - - void SetToZero() { - std::fill(words_, words_ + size_, 0u); - size_ = 0; - } - - // Returns the value of the nth word of this BigUnsigned. This is - // range-checked, and returns 0 on out-of-bounds accesses. - uint32_t GetWord(int index) const { - if (index < 0 || index >= size_) { - return 0; - } - return words_[index]; - } - + // Check for valid input, returning a 0 otherwise. This is reasonable + // behavior only because this constructor is for unit tests. + if (std::find_if_not(sv.begin(), sv.end(), ascii_isdigit) != sv.end() || + sv.empty()) { + return; + } + int exponent_adjust = + ReadDigits(sv.data(), sv.data() + sv.size(), Digits10() + 1); + if (exponent_adjust > 0) { + MultiplyByTenToTheNth(exponent_adjust); + } + } + + // Loads the mantissa value of a previously-parsed float. + // + // Returns the associated decimal exponent. The value of the parsed float is + // exactly *this * 10**exponent. + int ReadFloatMantissa(const ParsedFloat& fp, int significant_digits); + + // Returns the number of decimal digits of precision this type provides. All + // numbers with this many decimal digits or fewer are representable by this + // type. + // + // Analagous to std::numeric_limits<BigUnsigned>::digits10. + static constexpr int Digits10() { + // 9975007/1035508 is very slightly less than log10(2**32). + return static_cast<uint64_t>(max_words) * 9975007 / 1035508; + } + + // Shifts left by the given number of bits. + void ShiftLeft(int count) { + if (count > 0) { + const int word_shift = count / 32; + if (word_shift >= max_words) { + SetToZero(); + return; + } + size_ = (std::min)(size_ + word_shift, max_words); + count %= 32; + if (count == 0) { + std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_); + } else { + for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) { + words_[i] = (words_[i - word_shift] << count) | + (words_[i - word_shift - 1] >> (32 - count)); + } + words_[word_shift] = words_[0] << count; + // Grow size_ if necessary. + if (size_ < max_words && words_[size_]) { + ++size_; + } + } + std::fill(words_, words_ + word_shift, 0u); + } + } + + + // Multiplies by v in-place. + void MultiplyBy(uint32_t v) { + if (size_ == 0 || v == 1) { + return; + } + if (v == 0) { + SetToZero(); + return; + } + const uint64_t factor = v; + uint64_t window = 0; + for (int i = 0; i < size_; ++i) { + window += factor * words_[i]; + words_[i] = window & 0xffffffff; + window >>= 32; + } + // If carry bits remain and there's space for them, grow size_. + if (window && size_ < max_words) { + words_[size_] = window & 0xffffffff; + ++size_; + } + } + + void MultiplyBy(uint64_t v) { + uint32_t words[2]; + words[0] = static_cast<uint32_t>(v); + words[1] = static_cast<uint32_t>(v >> 32); + if (words[1] == 0) { + MultiplyBy(words[0]); + } else { + MultiplyBy(2, words); + } + } + + // Multiplies in place by 5 to the power of n. n must be non-negative. + void MultiplyByFiveToTheNth(int n) { + while (n >= kMaxSmallPowerOfFive) { + MultiplyBy(kFiveToNth[kMaxSmallPowerOfFive]); + n -= kMaxSmallPowerOfFive; + } + if (n > 0) { + MultiplyBy(kFiveToNth[n]); + } + } + + // Multiplies in place by 10 to the power of n. n must be non-negative. + void MultiplyByTenToTheNth(int n) { + if (n > kMaxSmallPowerOfTen) { + // For large n, raise to a power of 5, then shift left by the same amount. + // (10**n == 5**n * 2**n.) This requires fewer multiplications overall. + MultiplyByFiveToTheNth(n); + ShiftLeft(n); + } else if (n > 0) { + // We can do this more quickly for very small N by using a single + // multiplication. + MultiplyBy(kTenToNth[n]); + } + } + + // Returns the value of 5**n, for non-negative n. This implementation uses + // a lookup table, and is faster then seeding a BigUnsigned with 1 and calling + // MultiplyByFiveToTheNth(). + static BigUnsigned FiveToTheNth(int n); + + // Multiplies by another BigUnsigned, in-place. + template <int M> + void MultiplyBy(const BigUnsigned<M>& other) { + MultiplyBy(other.size(), other.words()); + } + + void SetToZero() { + std::fill(words_, words_ + size_, 0u); + size_ = 0; + } + + // Returns the value of the nth word of this BigUnsigned. This is + // range-checked, and returns 0 on out-of-bounds accesses. + uint32_t GetWord(int index) const { + if (index < 0 || index >= size_) { + return 0; + } + return words_[index]; + } + // Returns this integer as a decimal string. This is not used in the decimal- - // to-binary conversion; it is intended to aid in testing. + // to-binary conversion; it is intended to aid in testing. TString ToString() const; - - int size() const { return size_; } - const uint32_t* words() const { return words_; } - - private: - // Reads the number between [begin, end), possibly containing a decimal point, - // into this BigUnsigned. - // - // Callers are required to ensure [begin, end) contains a valid number, with - // one or more decimal digits and at most one decimal point. This routine - // will behave unpredictably if these preconditions are not met. - // - // Only the first `significant_digits` digits are read. Digits beyond this - // limit are "sticky": If the final significant digit is 0 or 5, and if any - // dropped digit is nonzero, then that final significant digit is adjusted up - // to 1 or 6. This adjustment allows for precise rounding. - // - // Returns `exponent_adjustment`, a power-of-ten exponent adjustment to - // account for the decimal point and for dropped significant digits. After - // this function returns, - // actual_value_of_parsed_string ~= *this * 10**exponent_adjustment. - int ReadDigits(const char* begin, const char* end, int significant_digits); - - // Performs a step of big integer multiplication. This computes the full - // (64-bit-wide) values that should be added at the given index (step), and - // adds to that location in-place. - // - // Because our math all occurs in place, we must multiply starting from the - // highest word working downward. (This is a bit more expensive due to the - // extra carries involved.) - // - // This must be called in steps, for each word to be calculated, starting from - // the high end and working down to 0. The first value of `step` should be - // `std::min(original_size + other.size_ - 2, max_words - 1)`. - // The reason for this expression is that multiplying the i'th word from one - // multiplicand and the j'th word of another multiplicand creates a - // two-word-wide value to be stored at the (i+j)'th element. The highest - // word indices we will access are `original_size - 1` from this object, and - // `other.size_ - 1` from our operand. Therefore, - // `original_size + other.size_ - 2` is the first step we should calculate, - // but limited on an upper bound by max_words. - - // Working from high-to-low ensures that we do not overwrite the portions of - // the initial value of *this which are still needed for later steps. - // - // Once called with step == 0, *this contains the result of the - // multiplication. - // - // `original_size` is the size_ of *this before the first call to - // MultiplyStep(). `other_words` and `other_size` are the contents of our - // operand. `step` is the step to perform, as described above. - void MultiplyStep(int original_size, const uint32_t* other_words, - int other_size, int step); - - void MultiplyBy(int other_size, const uint32_t* other_words) { - const int original_size = size_; - const int first_step = - (std::min)(original_size + other_size - 2, max_words - 1); - for (int step = first_step; step >= 0; --step) { - MultiplyStep(original_size, other_words, other_size, step); - } - } - - // Adds a 32-bit value to the index'th word, with carry. - void AddWithCarry(int index, uint32_t value) { - if (value) { - while (index < max_words && value > 0) { - words_[index] += value; - // carry if we overflowed in this word: - if (value > words_[index]) { - value = 1; - ++index; - } else { - value = 0; - } - } - size_ = (std::min)(max_words, (std::max)(index + 1, size_)); - } - } - - void AddWithCarry(int index, uint64_t value) { - if (value && index < max_words) { - uint32_t high = value >> 32; - uint32_t low = value & 0xffffffff; - words_[index] += low; - if (words_[index] < low) { - ++high; - if (high == 0) { - // Carry from the low word caused our high word to overflow. - // Short circuit here to do the right thing. - AddWithCarry(index + 2, static_cast<uint32_t>(1)); - return; - } - } - if (high > 0) { - AddWithCarry(index + 1, high); - } else { - // Normally 32-bit AddWithCarry() sets size_, but since we don't call - // it when `high` is 0, do it ourselves here. - size_ = (std::min)(max_words, (std::max)(index + 1, size_)); - } - } - } - - // Divide this in place by a constant divisor. Returns the remainder of the - // division. - template <uint32_t divisor> - uint32_t DivMod() { - uint64_t accumulator = 0; - for (int i = size_ - 1; i >= 0; --i) { - accumulator <<= 32; - accumulator += words_[i]; - // accumulator / divisor will never overflow an int32_t in this loop - words_[i] = static_cast<uint32_t>(accumulator / divisor); - accumulator = accumulator % divisor; - } - while (size_ > 0 && words_[size_ - 1] == 0) { - --size_; - } - return static_cast<uint32_t>(accumulator); - } - - // The number of elements in words_ that may carry significant values. - // All elements beyond this point are 0. - // - // When size_ is 0, this BigUnsigned stores the value 0. - // When size_ is nonzero, is *not* guaranteed that words_[size_ - 1] is - // nonzero. This can occur due to overflow truncation. - // In particular, x.size_ != y.size_ does *not* imply x != y. - int size_; - uint32_t words_[max_words]; -}; - -// Compares two big integer instances. -// -// Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs. -template <int N, int M> -int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - int limit = (std::max)(lhs.size(), rhs.size()); - for (int i = limit - 1; i >= 0; --i) { - const uint32_t lhs_word = lhs.GetWord(i); - const uint32_t rhs_word = rhs.GetWord(i); - if (lhs_word < rhs_word) { - return -1; - } else if (lhs_word > rhs_word) { - return 1; - } - } - return 0; -} - -template <int N, int M> -bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - int limit = (std::max)(lhs.size(), rhs.size()); - for (int i = 0; i < limit; ++i) { - if (lhs.GetWord(i) != rhs.GetWord(i)) { - return false; - } - } - return true; -} - -template <int N, int M> -bool operator!=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - return !(lhs == rhs); -} - -template <int N, int M> -bool operator<(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - return Compare(lhs, rhs) == -1; -} - -template <int N, int M> -bool operator>(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - return rhs < lhs; -} -template <int N, int M> -bool operator<=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - return !(rhs < lhs); -} -template <int N, int M> -bool operator>=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - return !(lhs < rhs); -} - -// Output operator for BigUnsigned, for testing purposes only. -template <int N> -std::ostream& operator<<(std::ostream& os, const BigUnsigned<N>& num) { - return os << num.ToString(); -} - -// Explicit instantiation declarations for the sizes of BigUnsigned that we -// are using. -// -// For now, the choices of 4 and 84 are arbitrary; 4 is a small value that is -// still bigger than an int128, and 84 is a large value we will want to use -// in the from_chars implementation. -// -// Comments justifying the use of 84 belong in the from_chars implementation, -// and will be added in a follow-up CL. -extern template class BigUnsigned<4>; -extern template class BigUnsigned<84>; - -} // namespace strings_internal + + int size() const { return size_; } + const uint32_t* words() const { return words_; } + + private: + // Reads the number between [begin, end), possibly containing a decimal point, + // into this BigUnsigned. + // + // Callers are required to ensure [begin, end) contains a valid number, with + // one or more decimal digits and at most one decimal point. This routine + // will behave unpredictably if these preconditions are not met. + // + // Only the first `significant_digits` digits are read. Digits beyond this + // limit are "sticky": If the final significant digit is 0 or 5, and if any + // dropped digit is nonzero, then that final significant digit is adjusted up + // to 1 or 6. This adjustment allows for precise rounding. + // + // Returns `exponent_adjustment`, a power-of-ten exponent adjustment to + // account for the decimal point and for dropped significant digits. After + // this function returns, + // actual_value_of_parsed_string ~= *this * 10**exponent_adjustment. + int ReadDigits(const char* begin, const char* end, int significant_digits); + + // Performs a step of big integer multiplication. This computes the full + // (64-bit-wide) values that should be added at the given index (step), and + // adds to that location in-place. + // + // Because our math all occurs in place, we must multiply starting from the + // highest word working downward. (This is a bit more expensive due to the + // extra carries involved.) + // + // This must be called in steps, for each word to be calculated, starting from + // the high end and working down to 0. The first value of `step` should be + // `std::min(original_size + other.size_ - 2, max_words - 1)`. + // The reason for this expression is that multiplying the i'th word from one + // multiplicand and the j'th word of another multiplicand creates a + // two-word-wide value to be stored at the (i+j)'th element. The highest + // word indices we will access are `original_size - 1` from this object, and + // `other.size_ - 1` from our operand. Therefore, + // `original_size + other.size_ - 2` is the first step we should calculate, + // but limited on an upper bound by max_words. + + // Working from high-to-low ensures that we do not overwrite the portions of + // the initial value of *this which are still needed for later steps. + // + // Once called with step == 0, *this contains the result of the + // multiplication. + // + // `original_size` is the size_ of *this before the first call to + // MultiplyStep(). `other_words` and `other_size` are the contents of our + // operand. `step` is the step to perform, as described above. + void MultiplyStep(int original_size, const uint32_t* other_words, + int other_size, int step); + + void MultiplyBy(int other_size, const uint32_t* other_words) { + const int original_size = size_; + const int first_step = + (std::min)(original_size + other_size - 2, max_words - 1); + for (int step = first_step; step >= 0; --step) { + MultiplyStep(original_size, other_words, other_size, step); + } + } + + // Adds a 32-bit value to the index'th word, with carry. + void AddWithCarry(int index, uint32_t value) { + if (value) { + while (index < max_words && value > 0) { + words_[index] += value; + // carry if we overflowed in this word: + if (value > words_[index]) { + value = 1; + ++index; + } else { + value = 0; + } + } + size_ = (std::min)(max_words, (std::max)(index + 1, size_)); + } + } + + void AddWithCarry(int index, uint64_t value) { + if (value && index < max_words) { + uint32_t high = value >> 32; + uint32_t low = value & 0xffffffff; + words_[index] += low; + if (words_[index] < low) { + ++high; + if (high == 0) { + // Carry from the low word caused our high word to overflow. + // Short circuit here to do the right thing. + AddWithCarry(index + 2, static_cast<uint32_t>(1)); + return; + } + } + if (high > 0) { + AddWithCarry(index + 1, high); + } else { + // Normally 32-bit AddWithCarry() sets size_, but since we don't call + // it when `high` is 0, do it ourselves here. + size_ = (std::min)(max_words, (std::max)(index + 1, size_)); + } + } + } + + // Divide this in place by a constant divisor. Returns the remainder of the + // division. + template <uint32_t divisor> + uint32_t DivMod() { + uint64_t accumulator = 0; + for (int i = size_ - 1; i >= 0; --i) { + accumulator <<= 32; + accumulator += words_[i]; + // accumulator / divisor will never overflow an int32_t in this loop + words_[i] = static_cast<uint32_t>(accumulator / divisor); + accumulator = accumulator % divisor; + } + while (size_ > 0 && words_[size_ - 1] == 0) { + --size_; + } + return static_cast<uint32_t>(accumulator); + } + + // The number of elements in words_ that may carry significant values. + // All elements beyond this point are 0. + // + // When size_ is 0, this BigUnsigned stores the value 0. + // When size_ is nonzero, is *not* guaranteed that words_[size_ - 1] is + // nonzero. This can occur due to overflow truncation. + // In particular, x.size_ != y.size_ does *not* imply x != y. + int size_; + uint32_t words_[max_words]; +}; + +// Compares two big integer instances. +// +// Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs. +template <int N, int M> +int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { + int limit = (std::max)(lhs.size(), rhs.size()); + for (int i = limit - 1; i >= 0; --i) { + const uint32_t lhs_word = lhs.GetWord(i); + const uint32_t rhs_word = rhs.GetWord(i); + if (lhs_word < rhs_word) { + return -1; + } else if (lhs_word > rhs_word) { + return 1; + } + } + return 0; +} + +template <int N, int M> +bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { + int limit = (std::max)(lhs.size(), rhs.size()); + for (int i = 0; i < limit; ++i) { + if (lhs.GetWord(i) != rhs.GetWord(i)) { + return false; + } + } + return true; +} + +template <int N, int M> +bool operator!=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { + return !(lhs == rhs); +} + +template <int N, int M> +bool operator<(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { + return Compare(lhs, rhs) == -1; +} + +template <int N, int M> +bool operator>(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { + return rhs < lhs; +} +template <int N, int M> +bool operator<=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { + return !(rhs < lhs); +} +template <int N, int M> +bool operator>=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { + return !(lhs < rhs); +} + +// Output operator for BigUnsigned, for testing purposes only. +template <int N> +std::ostream& operator<<(std::ostream& os, const BigUnsigned<N>& num) { + return os << num.ToString(); +} + +// Explicit instantiation declarations for the sizes of BigUnsigned that we +// are using. +// +// For now, the choices of 4 and 84 are arbitrary; 4 is a small value that is +// still bigger than an int128, and 84 is a large value we will want to use +// in the from_chars implementation. +// +// Comments justifying the use of 84 belong in the from_chars implementation, +// and will be added in a follow-up CL. +extern template class BigUnsigned<4>; +extern template class BigUnsigned<84>; + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ + +#endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc index f0f78eb68c..be60f962f5 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc @@ -1,504 +1,504 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/charconv_parse.h" #include "y_absl/strings/charconv.h" - -#include <cassert> -#include <cstdint> -#include <limits> - + +#include <cassert> +#include <cstdint> +#include <limits> + #include "y_absl/strings/internal/memutil.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace { - -// ParseFloat<10> will read the first 19 significant digits of the mantissa. -// This number was chosen for multiple reasons. -// -// (a) First, for whatever integer type we choose to represent the mantissa, we -// want to choose the largest possible number of decimal digits for that integer -// type. We are using uint64_t, which can express any 19-digit unsigned -// integer. -// -// (b) Second, we need to parse enough digits that the binary value of any -// mantissa we capture has more bits of resolution than the mantissa -// representation in the target float. Our algorithm requires at least 3 bits -// of headway, but 19 decimal digits give a little more than that. -// -// The following static assertions verify the above comments: -constexpr int kDecimalMantissaDigitsMax = 19; - -static_assert(std::numeric_limits<uint64_t>::digits10 == - kDecimalMantissaDigitsMax, - "(a) above"); - -// IEEE doubles, which we assume in Abseil, have 53 binary bits of mantissa. -static_assert(std::numeric_limits<double>::is_iec559, "IEEE double assumed"); -static_assert(std::numeric_limits<double>::radix == 2, "IEEE double fact"); -static_assert(std::numeric_limits<double>::digits == 53, "IEEE double fact"); - -// The lowest valued 19-digit decimal mantissa we can read still contains -// sufficient information to reconstruct a binary mantissa. +namespace { + +// ParseFloat<10> will read the first 19 significant digits of the mantissa. +// This number was chosen for multiple reasons. +// +// (a) First, for whatever integer type we choose to represent the mantissa, we +// want to choose the largest possible number of decimal digits for that integer +// type. We are using uint64_t, which can express any 19-digit unsigned +// integer. +// +// (b) Second, we need to parse enough digits that the binary value of any +// mantissa we capture has more bits of resolution than the mantissa +// representation in the target float. Our algorithm requires at least 3 bits +// of headway, but 19 decimal digits give a little more than that. +// +// The following static assertions verify the above comments: +constexpr int kDecimalMantissaDigitsMax = 19; + +static_assert(std::numeric_limits<uint64_t>::digits10 == + kDecimalMantissaDigitsMax, + "(a) above"); + +// IEEE doubles, which we assume in Abseil, have 53 binary bits of mantissa. +static_assert(std::numeric_limits<double>::is_iec559, "IEEE double assumed"); +static_assert(std::numeric_limits<double>::radix == 2, "IEEE double fact"); +static_assert(std::numeric_limits<double>::digits == 53, "IEEE double fact"); + +// The lowest valued 19-digit decimal mantissa we can read still contains +// sufficient information to reconstruct a binary mantissa. static_assert(1000000000000000000u > (uint64_t{1} << (53 + 3)), "(b) above"); - -// ParseFloat<16> will read the first 15 significant digits of the mantissa. -// -// Because a base-16-to-base-2 conversion can be done exactly, we do not need -// to maximize the number of scanned hex digits to improve our conversion. What -// is required is to scan two more bits than the mantissa can represent, so that -// we always round correctly. -// -// (One extra bit does not suffice to perform correct rounding, since a number -// exactly halfway between two representable floats has unique rounding rules, -// so we need to differentiate between a "halfway between" number and a "closer -// to the larger value" number.) -constexpr int kHexadecimalMantissaDigitsMax = 15; - -// The minimum number of significant bits that will be read from -// kHexadecimalMantissaDigitsMax hex digits. We must subtract by three, since -// the most significant digit can be a "1", which only contributes a single -// significant bit. -constexpr int kGuaranteedHexadecimalMantissaBitPrecision = - 4 * kHexadecimalMantissaDigitsMax - 3; - -static_assert(kGuaranteedHexadecimalMantissaBitPrecision > - std::numeric_limits<double>::digits + 2, - "kHexadecimalMantissaDigitsMax too small"); - -// We also impose a limit on the number of significant digits we will read from -// an exponent, to avoid having to deal with integer overflow. We use 9 for -// this purpose. -// -// If we read a 9 digit exponent, the end result of the conversion will -// necessarily be infinity or zero, depending on the sign of the exponent. -// Therefore we can just drop extra digits on the floor without any extra -// logic. -constexpr int kDecimalExponentDigitsMax = 9; -static_assert(std::numeric_limits<int>::digits10 >= kDecimalExponentDigitsMax, - "int type too small"); - -// To avoid incredibly large inputs causing integer overflow for our exponent, -// we impose an arbitrary but very large limit on the number of significant -// digits we will accept. The implementation refuses to match a string with -// more consecutive significant mantissa digits than this. -constexpr int kDecimalDigitLimit = 50000000; - -// Corresponding limit for hexadecimal digit inputs. This is one fourth the -// amount of kDecimalDigitLimit, since each dropped hexadecimal digit requires -// a binary exponent adjustment of 4. -constexpr int kHexadecimalDigitLimit = kDecimalDigitLimit / 4; - -// The largest exponent we can read is 999999999 (per -// kDecimalExponentDigitsMax), and the largest exponent adjustment we can get -// from dropped mantissa digits is 2 * kDecimalDigitLimit, and the sum of these -// comfortably fits in an integer. -// -// We count kDecimalDigitLimit twice because there are independent limits for -// numbers before and after the decimal point. (In the case where there are no -// significant digits before the decimal point, there are independent limits for -// post-decimal-point leading zeroes and for significant digits.) -static_assert(999999999 + 2 * kDecimalDigitLimit < - std::numeric_limits<int>::max(), - "int type too small"); -static_assert(999999999 + 2 * (4 * kHexadecimalDigitLimit) < - std::numeric_limits<int>::max(), - "int type too small"); - -// Returns true if the provided bitfield allows parsing an exponent value -// (e.g., "1.5e100"). -bool AllowExponent(chars_format flags) { - bool fixed = (flags & chars_format::fixed) == chars_format::fixed; - bool scientific = - (flags & chars_format::scientific) == chars_format::scientific; - return scientific || !fixed; -} - -// Returns true if the provided bitfield requires an exponent value be present. -bool RequireExponent(chars_format flags) { - bool fixed = (flags & chars_format::fixed) == chars_format::fixed; - bool scientific = - (flags & chars_format::scientific) == chars_format::scientific; - return scientific && !fixed; -} - -const int8_t kAsciiToInt[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, - 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; - -// Returns true if `ch` is a digit in the given base -template <int base> -bool IsDigit(char ch); - -// Converts a valid `ch` to its digit value in the given base. -template <int base> -unsigned ToDigit(char ch); - -// Returns true if `ch` is the exponent delimiter for the given base. -template <int base> -bool IsExponentCharacter(char ch); - -// Returns the maximum number of significant digits we will read for a float -// in the given base. -template <int base> -constexpr int MantissaDigitsMax(); - -// Returns the largest consecutive run of digits we will accept when parsing a -// number in the given base. -template <int base> -constexpr int DigitLimit(); - -// Returns the amount the exponent must be adjusted by for each dropped digit. -// (For decimal this is 1, since the digits are in base 10 and the exponent base -// is also 10, but for hexadecimal this is 4, since the digits are base 16 but -// the exponent base is 2.) -template <int base> -constexpr int DigitMagnitude(); - -template <> -bool IsDigit<10>(char ch) { - return ch >= '0' && ch <= '9'; -} -template <> -bool IsDigit<16>(char ch) { - return kAsciiToInt[static_cast<unsigned char>(ch)] >= 0; -} - -template <> -unsigned ToDigit<10>(char ch) { - return ch - '0'; -} -template <> -unsigned ToDigit<16>(char ch) { - return kAsciiToInt[static_cast<unsigned char>(ch)]; -} - -template <> -bool IsExponentCharacter<10>(char ch) { - return ch == 'e' || ch == 'E'; -} - -template <> -bool IsExponentCharacter<16>(char ch) { - return ch == 'p' || ch == 'P'; -} - -template <> -constexpr int MantissaDigitsMax<10>() { - return kDecimalMantissaDigitsMax; -} -template <> -constexpr int MantissaDigitsMax<16>() { - return kHexadecimalMantissaDigitsMax; -} - -template <> -constexpr int DigitLimit<10>() { - return kDecimalDigitLimit; -} -template <> -constexpr int DigitLimit<16>() { - return kHexadecimalDigitLimit; -} - -template <> -constexpr int DigitMagnitude<10>() { - return 1; -} -template <> -constexpr int DigitMagnitude<16>() { - return 4; -} - -// Reads decimal digits from [begin, end) into *out. Returns the number of -// digits consumed. -// -// After max_digits has been read, keeps consuming characters, but no longer -// adjusts *out. If a nonzero digit is dropped this way, *dropped_nonzero_digit -// is set; otherwise, it is left unmodified. -// -// If no digits are matched, returns 0 and leaves *out unchanged. -// -// ConsumeDigits does not protect against overflow on *out; max_digits must -// be chosen with respect to type T to avoid the possibility of overflow. -template <int base, typename T> + +// ParseFloat<16> will read the first 15 significant digits of the mantissa. +// +// Because a base-16-to-base-2 conversion can be done exactly, we do not need +// to maximize the number of scanned hex digits to improve our conversion. What +// is required is to scan two more bits than the mantissa can represent, so that +// we always round correctly. +// +// (One extra bit does not suffice to perform correct rounding, since a number +// exactly halfway between two representable floats has unique rounding rules, +// so we need to differentiate between a "halfway between" number and a "closer +// to the larger value" number.) +constexpr int kHexadecimalMantissaDigitsMax = 15; + +// The minimum number of significant bits that will be read from +// kHexadecimalMantissaDigitsMax hex digits. We must subtract by three, since +// the most significant digit can be a "1", which only contributes a single +// significant bit. +constexpr int kGuaranteedHexadecimalMantissaBitPrecision = + 4 * kHexadecimalMantissaDigitsMax - 3; + +static_assert(kGuaranteedHexadecimalMantissaBitPrecision > + std::numeric_limits<double>::digits + 2, + "kHexadecimalMantissaDigitsMax too small"); + +// We also impose a limit on the number of significant digits we will read from +// an exponent, to avoid having to deal with integer overflow. We use 9 for +// this purpose. +// +// If we read a 9 digit exponent, the end result of the conversion will +// necessarily be infinity or zero, depending on the sign of the exponent. +// Therefore we can just drop extra digits on the floor without any extra +// logic. +constexpr int kDecimalExponentDigitsMax = 9; +static_assert(std::numeric_limits<int>::digits10 >= kDecimalExponentDigitsMax, + "int type too small"); + +// To avoid incredibly large inputs causing integer overflow for our exponent, +// we impose an arbitrary but very large limit on the number of significant +// digits we will accept. The implementation refuses to match a string with +// more consecutive significant mantissa digits than this. +constexpr int kDecimalDigitLimit = 50000000; + +// Corresponding limit for hexadecimal digit inputs. This is one fourth the +// amount of kDecimalDigitLimit, since each dropped hexadecimal digit requires +// a binary exponent adjustment of 4. +constexpr int kHexadecimalDigitLimit = kDecimalDigitLimit / 4; + +// The largest exponent we can read is 999999999 (per +// kDecimalExponentDigitsMax), and the largest exponent adjustment we can get +// from dropped mantissa digits is 2 * kDecimalDigitLimit, and the sum of these +// comfortably fits in an integer. +// +// We count kDecimalDigitLimit twice because there are independent limits for +// numbers before and after the decimal point. (In the case where there are no +// significant digits before the decimal point, there are independent limits for +// post-decimal-point leading zeroes and for significant digits.) +static_assert(999999999 + 2 * kDecimalDigitLimit < + std::numeric_limits<int>::max(), + "int type too small"); +static_assert(999999999 + 2 * (4 * kHexadecimalDigitLimit) < + std::numeric_limits<int>::max(), + "int type too small"); + +// Returns true if the provided bitfield allows parsing an exponent value +// (e.g., "1.5e100"). +bool AllowExponent(chars_format flags) { + bool fixed = (flags & chars_format::fixed) == chars_format::fixed; + bool scientific = + (flags & chars_format::scientific) == chars_format::scientific; + return scientific || !fixed; +} + +// Returns true if the provided bitfield requires an exponent value be present. +bool RequireExponent(chars_format flags) { + bool fixed = (flags & chars_format::fixed) == chars_format::fixed; + bool scientific = + (flags & chars_format::scientific) == chars_format::scientific; + return scientific && !fixed; +} + +const int8_t kAsciiToInt[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}; + +// Returns true if `ch` is a digit in the given base +template <int base> +bool IsDigit(char ch); + +// Converts a valid `ch` to its digit value in the given base. +template <int base> +unsigned ToDigit(char ch); + +// Returns true if `ch` is the exponent delimiter for the given base. +template <int base> +bool IsExponentCharacter(char ch); + +// Returns the maximum number of significant digits we will read for a float +// in the given base. +template <int base> +constexpr int MantissaDigitsMax(); + +// Returns the largest consecutive run of digits we will accept when parsing a +// number in the given base. +template <int base> +constexpr int DigitLimit(); + +// Returns the amount the exponent must be adjusted by for each dropped digit. +// (For decimal this is 1, since the digits are in base 10 and the exponent base +// is also 10, but for hexadecimal this is 4, since the digits are base 16 but +// the exponent base is 2.) +template <int base> +constexpr int DigitMagnitude(); + +template <> +bool IsDigit<10>(char ch) { + return ch >= '0' && ch <= '9'; +} +template <> +bool IsDigit<16>(char ch) { + return kAsciiToInt[static_cast<unsigned char>(ch)] >= 0; +} + +template <> +unsigned ToDigit<10>(char ch) { + return ch - '0'; +} +template <> +unsigned ToDigit<16>(char ch) { + return kAsciiToInt[static_cast<unsigned char>(ch)]; +} + +template <> +bool IsExponentCharacter<10>(char ch) { + return ch == 'e' || ch == 'E'; +} + +template <> +bool IsExponentCharacter<16>(char ch) { + return ch == 'p' || ch == 'P'; +} + +template <> +constexpr int MantissaDigitsMax<10>() { + return kDecimalMantissaDigitsMax; +} +template <> +constexpr int MantissaDigitsMax<16>() { + return kHexadecimalMantissaDigitsMax; +} + +template <> +constexpr int DigitLimit<10>() { + return kDecimalDigitLimit; +} +template <> +constexpr int DigitLimit<16>() { + return kHexadecimalDigitLimit; +} + +template <> +constexpr int DigitMagnitude<10>() { + return 1; +} +template <> +constexpr int DigitMagnitude<16>() { + return 4; +} + +// Reads decimal digits from [begin, end) into *out. Returns the number of +// digits consumed. +// +// After max_digits has been read, keeps consuming characters, but no longer +// adjusts *out. If a nonzero digit is dropped this way, *dropped_nonzero_digit +// is set; otherwise, it is left unmodified. +// +// If no digits are matched, returns 0 and leaves *out unchanged. +// +// ConsumeDigits does not protect against overflow on *out; max_digits must +// be chosen with respect to type T to avoid the possibility of overflow. +template <int base, typename T> int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out, bool* dropped_nonzero_digit) { - if (base == 10) { - assert(max_digits <= std::numeric_limits<T>::digits10); - } else if (base == 16) { - assert(max_digits * 4 <= std::numeric_limits<T>::digits); - } - const char* const original_begin = begin; - - // Skip leading zeros, but only if *out is zero. - // They don't cause an overflow so we don't have to count them for - // `max_digits`. - while (!*out && end != begin && *begin == '0') ++begin; - - T accumulator = *out; - const char* significant_digits_end = - (end - begin > max_digits) ? begin + max_digits : end; - while (begin < significant_digits_end && IsDigit<base>(*begin)) { - // Do not guard against *out overflow; max_digits was chosen to avoid this. - // Do assert against it, to detect problems in debug builds. - auto digit = static_cast<T>(ToDigit<base>(*begin)); - assert(accumulator * base >= accumulator); - accumulator *= base; - assert(accumulator + digit >= accumulator); - accumulator += digit; - ++begin; - } - bool dropped_nonzero = false; - while (begin < end && IsDigit<base>(*begin)) { - dropped_nonzero = dropped_nonzero || (*begin != '0'); - ++begin; - } - if (dropped_nonzero && dropped_nonzero_digit != nullptr) { - *dropped_nonzero_digit = true; - } - *out = accumulator; + if (base == 10) { + assert(max_digits <= std::numeric_limits<T>::digits10); + } else if (base == 16) { + assert(max_digits * 4 <= std::numeric_limits<T>::digits); + } + const char* const original_begin = begin; + + // Skip leading zeros, but only if *out is zero. + // They don't cause an overflow so we don't have to count them for + // `max_digits`. + while (!*out && end != begin && *begin == '0') ++begin; + + T accumulator = *out; + const char* significant_digits_end = + (end - begin > max_digits) ? begin + max_digits : end; + while (begin < significant_digits_end && IsDigit<base>(*begin)) { + // Do not guard against *out overflow; max_digits was chosen to avoid this. + // Do assert against it, to detect problems in debug builds. + auto digit = static_cast<T>(ToDigit<base>(*begin)); + assert(accumulator * base >= accumulator); + accumulator *= base; + assert(accumulator + digit >= accumulator); + accumulator += digit; + ++begin; + } + bool dropped_nonzero = false; + while (begin < end && IsDigit<base>(*begin)) { + dropped_nonzero = dropped_nonzero || (*begin != '0'); + ++begin; + } + if (dropped_nonzero && dropped_nonzero_digit != nullptr) { + *dropped_nonzero_digit = true; + } + *out = accumulator; return static_cast<int>(begin - original_begin); -} - -// Returns true if `v` is one of the chars allowed inside parentheses following -// a NaN. -bool IsNanChar(char v) { - return (v == '_') || (v >= '0' && v <= '9') || (v >= 'a' && v <= 'z') || - (v >= 'A' && v <= 'Z'); -} - -// Checks the range [begin, end) for a strtod()-formatted infinity or NaN. If -// one is found, sets `out` appropriately and returns true. -bool ParseInfinityOrNan(const char* begin, const char* end, - strings_internal::ParsedFloat* out) { - if (end - begin < 3) { - return false; - } - switch (*begin) { - case 'i': - case 'I': { +} + +// Returns true if `v` is one of the chars allowed inside parentheses following +// a NaN. +bool IsNanChar(char v) { + return (v == '_') || (v >= '0' && v <= '9') || (v >= 'a' && v <= 'z') || + (v >= 'A' && v <= 'Z'); +} + +// Checks the range [begin, end) for a strtod()-formatted infinity or NaN. If +// one is found, sets `out` appropriately and returns true. +bool ParseInfinityOrNan(const char* begin, const char* end, + strings_internal::ParsedFloat* out) { + if (end - begin < 3) { + return false; + } + switch (*begin) { + case 'i': + case 'I': { // An infinity string consists of the characters "inf" or "infinity", - // case insensitive. - if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) { - return false; - } - out->type = strings_internal::FloatType::kInfinity; - if (end - begin >= 8 && - strings_internal::memcasecmp(begin + 3, "inity", 5) == 0) { - out->end = begin + 8; - } else { - out->end = begin + 3; - } - return true; - } - case 'n': - case 'N': { - // A NaN consists of the characters "nan", case insensitive, optionally - // followed by a parenthesized sequence of zero or more alphanumeric - // characters and/or underscores. - if (strings_internal::memcasecmp(begin + 1, "an", 2) != 0) { - return false; - } - out->type = strings_internal::FloatType::kNan; - out->end = begin + 3; + // case insensitive. + if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) { + return false; + } + out->type = strings_internal::FloatType::kInfinity; + if (end - begin >= 8 && + strings_internal::memcasecmp(begin + 3, "inity", 5) == 0) { + out->end = begin + 8; + } else { + out->end = begin + 3; + } + return true; + } + case 'n': + case 'N': { + // A NaN consists of the characters "nan", case insensitive, optionally + // followed by a parenthesized sequence of zero or more alphanumeric + // characters and/or underscores. + if (strings_internal::memcasecmp(begin + 1, "an", 2) != 0) { + return false; + } + out->type = strings_internal::FloatType::kNan; + out->end = begin + 3; // NaN is allowed to be followed by a parenthesized string, consisting of - // only the characters [a-zA-Z0-9_]. Match that if it's present. - begin += 3; - if (begin < end && *begin == '(') { - const char* nan_begin = begin + 1; - while (nan_begin < end && IsNanChar(*nan_begin)) { - ++nan_begin; - } - if (nan_begin < end && *nan_begin == ')') { - // We found an extra NaN specifier range - out->subrange_begin = begin + 1; - out->subrange_end = nan_begin; - out->end = nan_begin + 1; - } - } - return true; - } - default: - return false; - } -} -} // namespace - -namespace strings_internal { - -template <int base> -strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end, - chars_format format_flags) { - strings_internal::ParsedFloat result; - - // Exit early if we're given an empty range. - if (begin == end) return result; - - // Handle the infinity and NaN cases. - if (ParseInfinityOrNan(begin, end, &result)) { - return result; - } - - const char* const mantissa_begin = begin; - while (begin < end && *begin == '0') { - ++begin; // skip leading zeros - } - uint64_t mantissa = 0; - - int exponent_adjustment = 0; - bool mantissa_is_inexact = false; + // only the characters [a-zA-Z0-9_]. Match that if it's present. + begin += 3; + if (begin < end && *begin == '(') { + const char* nan_begin = begin + 1; + while (nan_begin < end && IsNanChar(*nan_begin)) { + ++nan_begin; + } + if (nan_begin < end && *nan_begin == ')') { + // We found an extra NaN specifier range + out->subrange_begin = begin + 1; + out->subrange_end = nan_begin; + out->end = nan_begin + 1; + } + } + return true; + } + default: + return false; + } +} +} // namespace + +namespace strings_internal { + +template <int base> +strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end, + chars_format format_flags) { + strings_internal::ParsedFloat result; + + // Exit early if we're given an empty range. + if (begin == end) return result; + + // Handle the infinity and NaN cases. + if (ParseInfinityOrNan(begin, end, &result)) { + return result; + } + + const char* const mantissa_begin = begin; + while (begin < end && *begin == '0') { + ++begin; // skip leading zeros + } + uint64_t mantissa = 0; + + int exponent_adjustment = 0; + bool mantissa_is_inexact = false; int pre_decimal_digits = ConsumeDigits<base>( - begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact); - begin += pre_decimal_digits; - int digits_left; - if (pre_decimal_digits >= DigitLimit<base>()) { - // refuse to parse pathological inputs - return result; - } else if (pre_decimal_digits > MantissaDigitsMax<base>()) { - // We dropped some non-fraction digits on the floor. Adjust our exponent - // to compensate. - exponent_adjustment = - static_cast<int>(pre_decimal_digits - MantissaDigitsMax<base>()); - digits_left = 0; - } else { - digits_left = - static_cast<int>(MantissaDigitsMax<base>() - pre_decimal_digits); - } - if (begin < end && *begin == '.') { - ++begin; - if (mantissa == 0) { - // If we haven't seen any nonzero digits yet, keep skipping zeros. We - // have to adjust the exponent to reflect the changed place value. - const char* begin_zeros = begin; - while (begin < end && *begin == '0') { - ++begin; - } + begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact); + begin += pre_decimal_digits; + int digits_left; + if (pre_decimal_digits >= DigitLimit<base>()) { + // refuse to parse pathological inputs + return result; + } else if (pre_decimal_digits > MantissaDigitsMax<base>()) { + // We dropped some non-fraction digits on the floor. Adjust our exponent + // to compensate. + exponent_adjustment = + static_cast<int>(pre_decimal_digits - MantissaDigitsMax<base>()); + digits_left = 0; + } else { + digits_left = + static_cast<int>(MantissaDigitsMax<base>() - pre_decimal_digits); + } + if (begin < end && *begin == '.') { + ++begin; + if (mantissa == 0) { + // If we haven't seen any nonzero digits yet, keep skipping zeros. We + // have to adjust the exponent to reflect the changed place value. + const char* begin_zeros = begin; + while (begin < end && *begin == '0') { + ++begin; + } int zeros_skipped = static_cast<int>(begin - begin_zeros); - if (zeros_skipped >= DigitLimit<base>()) { - // refuse to parse pathological inputs - return result; - } - exponent_adjustment -= static_cast<int>(zeros_skipped); - } + if (zeros_skipped >= DigitLimit<base>()) { + // refuse to parse pathological inputs + return result; + } + exponent_adjustment -= static_cast<int>(zeros_skipped); + } int post_decimal_digits = ConsumeDigits<base>( - begin, end, digits_left, &mantissa, &mantissa_is_inexact); - begin += post_decimal_digits; - - // Since `mantissa` is an integer, each significant digit we read after - // the decimal point requires an adjustment to the exponent. "1.23e0" will - // be stored as `mantissa` == 123 and `exponent` == -2 (that is, - // "123e-2"). - if (post_decimal_digits >= DigitLimit<base>()) { - // refuse to parse pathological inputs - return result; - } else if (post_decimal_digits > digits_left) { - exponent_adjustment -= digits_left; - } else { - exponent_adjustment -= post_decimal_digits; - } - } - // If we've found no mantissa whatsoever, this isn't a number. - if (mantissa_begin == begin) { - return result; - } - // A bare "." doesn't count as a mantissa either. - if (begin - mantissa_begin == 1 && *mantissa_begin == '.') { - return result; - } - - if (mantissa_is_inexact) { - // We dropped significant digits on the floor. Handle this appropriately. - if (base == 10) { - // If we truncated significant decimal digits, store the full range of the - // mantissa for future big integer math for exact rounding. - result.subrange_begin = mantissa_begin; - result.subrange_end = begin; - } else if (base == 16) { - // If we truncated hex digits, reflect this fact by setting the low - // ("sticky") bit. This allows for correct rounding in all cases. - mantissa |= 1; - } - } - result.mantissa = mantissa; - - const char* const exponent_begin = begin; - result.literal_exponent = 0; - bool found_exponent = false; - if (AllowExponent(format_flags) && begin < end && - IsExponentCharacter<base>(*begin)) { - bool negative_exponent = false; - ++begin; - if (begin < end && *begin == '-') { - negative_exponent = true; - ++begin; - } else if (begin < end && *begin == '+') { - ++begin; - } - const char* const exponent_digits_begin = begin; - // Exponent is always expressed in decimal, even for hexadecimal floats. - begin += ConsumeDigits<10>(begin, end, kDecimalExponentDigitsMax, - &result.literal_exponent, nullptr); - if (begin == exponent_digits_begin) { - // there were no digits where we expected an exponent. We failed to read - // an exponent and should not consume the 'e' after all. Rewind 'begin'. - found_exponent = false; - begin = exponent_begin; - } else { - found_exponent = true; - if (negative_exponent) { - result.literal_exponent = -result.literal_exponent; - } - } - } - - if (!found_exponent && RequireExponent(format_flags)) { - // Provided flags required an exponent, but none was found. This results - // in a failure to scan. - return result; - } - - // Success! - result.type = strings_internal::FloatType::kNumber; - if (result.mantissa > 0) { - result.exponent = result.literal_exponent + - (DigitMagnitude<base>() * exponent_adjustment); - } else { - result.exponent = 0; - } - result.end = begin; - return result; -} - -template ParsedFloat ParseFloat<10>(const char* begin, const char* end, - chars_format format_flags); -template ParsedFloat ParseFloat<16>(const char* begin, const char* end, - chars_format format_flags); - -} // namespace strings_internal + begin, end, digits_left, &mantissa, &mantissa_is_inexact); + begin += post_decimal_digits; + + // Since `mantissa` is an integer, each significant digit we read after + // the decimal point requires an adjustment to the exponent. "1.23e0" will + // be stored as `mantissa` == 123 and `exponent` == -2 (that is, + // "123e-2"). + if (post_decimal_digits >= DigitLimit<base>()) { + // refuse to parse pathological inputs + return result; + } else if (post_decimal_digits > digits_left) { + exponent_adjustment -= digits_left; + } else { + exponent_adjustment -= post_decimal_digits; + } + } + // If we've found no mantissa whatsoever, this isn't a number. + if (mantissa_begin == begin) { + return result; + } + // A bare "." doesn't count as a mantissa either. + if (begin - mantissa_begin == 1 && *mantissa_begin == '.') { + return result; + } + + if (mantissa_is_inexact) { + // We dropped significant digits on the floor. Handle this appropriately. + if (base == 10) { + // If we truncated significant decimal digits, store the full range of the + // mantissa for future big integer math for exact rounding. + result.subrange_begin = mantissa_begin; + result.subrange_end = begin; + } else if (base == 16) { + // If we truncated hex digits, reflect this fact by setting the low + // ("sticky") bit. This allows for correct rounding in all cases. + mantissa |= 1; + } + } + result.mantissa = mantissa; + + const char* const exponent_begin = begin; + result.literal_exponent = 0; + bool found_exponent = false; + if (AllowExponent(format_flags) && begin < end && + IsExponentCharacter<base>(*begin)) { + bool negative_exponent = false; + ++begin; + if (begin < end && *begin == '-') { + negative_exponent = true; + ++begin; + } else if (begin < end && *begin == '+') { + ++begin; + } + const char* const exponent_digits_begin = begin; + // Exponent is always expressed in decimal, even for hexadecimal floats. + begin += ConsumeDigits<10>(begin, end, kDecimalExponentDigitsMax, + &result.literal_exponent, nullptr); + if (begin == exponent_digits_begin) { + // there were no digits where we expected an exponent. We failed to read + // an exponent and should not consume the 'e' after all. Rewind 'begin'. + found_exponent = false; + begin = exponent_begin; + } else { + found_exponent = true; + if (negative_exponent) { + result.literal_exponent = -result.literal_exponent; + } + } + } + + if (!found_exponent && RequireExponent(format_flags)) { + // Provided flags required an exponent, but none was found. This results + // in a failure to scan. + return result; + } + + // Success! + result.type = strings_internal::FloatType::kNumber; + if (result.mantissa > 0) { + result.exponent = result.literal_exponent + + (DigitMagnitude<base>() * exponent_adjustment); + } else { + result.exponent = 0; + } + result.end = begin; + return result; +} + +template ParsedFloat ParseFloat<10>(const char* begin, const char* end, + chars_format format_flags); +template ParsedFloat ParseFloat<16>(const char* begin, const char* end, + chars_format format_flags); + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.h index 3f942cd4cb..2e5a9d1f2e 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.h @@ -1,99 +1,99 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ -#define ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ - -#include <cstdint> - +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ +#define ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ + +#include <cstdint> + #include "y_absl/base/config.h" #include "y_absl/strings/charconv.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -// Enum indicating whether a parsed float is a number or special value. -enum class FloatType { kNumber, kInfinity, kNan }; - -// The decomposed parts of a parsed `float` or `double`. -struct ParsedFloat { - // Representation of the parsed mantissa, with the decimal point adjusted to - // make it an integer. - // - // During decimal scanning, this contains 19 significant digits worth of - // mantissa value. If digits beyond this point are found, they - // are truncated, and if any of these dropped digits are nonzero, then - // `mantissa` is inexact, and the full mantissa is stored in [subrange_begin, - // subrange_end). - // - // During hexadecimal scanning, this contains 15 significant hex digits worth - // of mantissa value. Digits beyond this point are sticky -- they are - // truncated, but if any dropped digits are nonzero, the low bit of mantissa - // will be set. (This allows for precise rounding, and avoids the need - // to store the full mantissa in [subrange_begin, subrange_end).) - uint64_t mantissa = 0; - - // Floating point expontent. This reflects any decimal point adjustments and - // any truncated digits from the mantissa. The absolute value of the parsed - // number is represented by mantissa * (base ** exponent), where base==10 for - // decimal floats, and base==2 for hexadecimal floats. - int exponent = 0; - - // The literal exponent value scanned from the input, or 0 if none was - // present. This does not reflect any adjustments applied to mantissa. - int literal_exponent = 0; - - // The type of number scanned. - FloatType type = FloatType::kNumber; - - // When non-null, [subrange_begin, subrange_end) marks a range of characters - // that require further processing. The meaning is dependent on float type. - // If type == kNumber and this is set, this is a "wide input": the input - // mantissa contained more than 19 digits. The range contains the full - // mantissa. It plus `literal_exponent` need to be examined to find the best - // floating point match. - // If type == kNan and this is set, the range marks the contents of a - // matched parenthesized character region after the NaN. - const char* subrange_begin = nullptr; - const char* subrange_end = nullptr; - - // One-past-the-end of the successfully parsed region, or nullptr if no - // matching pattern was found. - const char* end = nullptr; -}; - -// Read the floating point number in the provided range, and populate -// ParsedFloat accordingly. -// -// format_flags is a bitmask value specifying what patterns this API will match. -// `scientific` and `fixed` are honored per std::from_chars rules -// ([utility.from.chars], C++17): if exactly one of these bits is set, then an -// exponent is required, or dislallowed, respectively. -// -// Template parameter `base` must be either 10 or 16. For base 16, a "0x" is -// *not* consumed. The `hex` bit from format_flags is ignored by ParseFloat. -template <int base> -ParsedFloat ParseFloat(const char* begin, const char* end, +namespace strings_internal { + +// Enum indicating whether a parsed float is a number or special value. +enum class FloatType { kNumber, kInfinity, kNan }; + +// The decomposed parts of a parsed `float` or `double`. +struct ParsedFloat { + // Representation of the parsed mantissa, with the decimal point adjusted to + // make it an integer. + // + // During decimal scanning, this contains 19 significant digits worth of + // mantissa value. If digits beyond this point are found, they + // are truncated, and if any of these dropped digits are nonzero, then + // `mantissa` is inexact, and the full mantissa is stored in [subrange_begin, + // subrange_end). + // + // During hexadecimal scanning, this contains 15 significant hex digits worth + // of mantissa value. Digits beyond this point are sticky -- they are + // truncated, but if any dropped digits are nonzero, the low bit of mantissa + // will be set. (This allows for precise rounding, and avoids the need + // to store the full mantissa in [subrange_begin, subrange_end).) + uint64_t mantissa = 0; + + // Floating point expontent. This reflects any decimal point adjustments and + // any truncated digits from the mantissa. The absolute value of the parsed + // number is represented by mantissa * (base ** exponent), where base==10 for + // decimal floats, and base==2 for hexadecimal floats. + int exponent = 0; + + // The literal exponent value scanned from the input, or 0 if none was + // present. This does not reflect any adjustments applied to mantissa. + int literal_exponent = 0; + + // The type of number scanned. + FloatType type = FloatType::kNumber; + + // When non-null, [subrange_begin, subrange_end) marks a range of characters + // that require further processing. The meaning is dependent on float type. + // If type == kNumber and this is set, this is a "wide input": the input + // mantissa contained more than 19 digits. The range contains the full + // mantissa. It plus `literal_exponent` need to be examined to find the best + // floating point match. + // If type == kNan and this is set, the range marks the contents of a + // matched parenthesized character region after the NaN. + const char* subrange_begin = nullptr; + const char* subrange_end = nullptr; + + // One-past-the-end of the successfully parsed region, or nullptr if no + // matching pattern was found. + const char* end = nullptr; +}; + +// Read the floating point number in the provided range, and populate +// ParsedFloat accordingly. +// +// format_flags is a bitmask value specifying what patterns this API will match. +// `scientific` and `fixed` are honored per std::from_chars rules +// ([utility.from.chars], C++17): if exactly one of these bits is set, then an +// exponent is required, or dislallowed, respectively. +// +// Template parameter `base` must be either 10 or 16. For base 16, a "0x" is +// *not* consumed. The `hex` bit from format_flags is ignored by ParseFloat. +template <int base> +ParsedFloat ParseFloat(const char* begin, const char* end, y_absl::chars_format format_flags); - -extern template ParsedFloat ParseFloat<10>(const char* begin, const char* end, + +extern template ParsedFloat ParseFloat<10>(const char* begin, const char* end, y_absl::chars_format format_flags); -extern template ParsedFloat ParseFloat<16>(const char* begin, const char* end, +extern template ParsedFloat ParseFloat<16>(const char* begin, const char* end, y_absl::chars_format format_flags); - -} // namespace strings_internal + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl -#endif // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ +#endif // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make index 06e99346da..c6d435bed7 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make @@ -1,16 +1,16 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() - + OWNER( somov g:cpp-contrib ) -LICENSE(Apache-2.0) - +LICENSE(Apache-2.0) + PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity @@ -20,13 +20,13 @@ PEERDIR( ADDINCL( GLOBAL contrib/restricted/abseil-cpp-tstring ) - -NO_COMPILER_WARNINGS() - + +NO_COMPILER_WARNINGS() + SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal) - -SRCS( + +SRCS( cordz_functions.cc -) - -END() +) + +END() diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/escaping_test_common.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/escaping_test_common.h index f145127225..1268b3a64d 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/escaping_test_common.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/escaping_test_common.h @@ -1,133 +1,133 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This test contains common things needed by both escaping_test.cc and -// escaping_benchmark.cc. - -#ifndef ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ -#define ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ - -#include <array> +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This test contains common things needed by both escaping_test.cc and +// escaping_benchmark.cc. + +#ifndef ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ +#define ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ + +#include <array> #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -struct base64_testcase { +namespace strings_internal { + +struct base64_testcase { y_absl::string_view plaintext; y_absl::string_view cyphertext; -}; - -inline const std::array<base64_testcase, 5>& base64_strings() { - static const std::array<base64_testcase, 5> testcase{{ - // Some google quotes - // Cyphertext created with "uuencode (GNU sharutils) 4.6.3" - // (Note that we're testing the websafe encoding, though, so if - // you add messages, be sure to run "tr -- '+/' '-_'" on the output) - { "I was always good at math and science, and I never realized " - "that was unusual or somehow undesirable. So one of the things " - "I care a lot about is helping to remove that stigma, " - "to show girls that you can be feminine, you can like the things " - "that girls like, but you can also be really good at technology. " - "You can be really good at building things." - " - Marissa Meyer, Newsweek, 2010-12-22" "\n", - - "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg" - "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu" - "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg" - "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo" - "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp" - "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs" - "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy" - "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll" - "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" }, - - { "Typical first year for a new cluster: " - "~0.5 overheating " - "~1 PDU failure " - "~1 rack-move " - "~1 network rewiring " - "~20 rack failures " - "~5 racks go wonky " - "~8 network maintenances " - "~12 router reloads " - "~3 router failures " - "~dozens of minor 30-second blips for dns " - "~1000 individual machine failures " - "~thousands of hard drive failures " - "slow disks, bad memory, misconfigured machines, flaky machines, etc." - " - Jeff Dean, The Joys of Real Hardware" "\n", - - "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92" - "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3" - "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv" - "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk" - "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv" - "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp" - "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg" - "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs" - "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS" - "ZWFsIEhhcmR3YXJlCg" }, - - { "I'm the head of the webspam team at Google. " - "That means that if you type your name into Google and get porn back, " - "it's my fault. Unless you're a porn star, in which case porn is a " - "completely reasonable response." - " - Matt Cutts, Google Plus" "\n", - - "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg" - "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv" - "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz" - "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg" - "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs" - "IEdvb2dsZSBQbHVzCg" }, - - { "It will still be a long time before machines approach human " - "intelligence. " - "But luckily, machines don't actually have to be intelligent; " - "they just have to fake it. Access to a wealth of information, " - "combined with a rudimentary decision-making capacity, " - "can often be almost as useful. Of course, the results are better yet " - "when coupled with intelligence. A reference librarian with access to " - "a good search engine is a formidable tool." - " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" - "\n", - - "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg" - "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj" - "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg" - "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo" - "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg" - "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0" - "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy" - "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl" - "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu" - "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp" - "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw" - "NAo" }, - - // Degenerate edge case - { "", - "" }, - }}; - - return testcase; -} - -} // namespace strings_internal +}; + +inline const std::array<base64_testcase, 5>& base64_strings() { + static const std::array<base64_testcase, 5> testcase{{ + // Some google quotes + // Cyphertext created with "uuencode (GNU sharutils) 4.6.3" + // (Note that we're testing the websafe encoding, though, so if + // you add messages, be sure to run "tr -- '+/' '-_'" on the output) + { "I was always good at math and science, and I never realized " + "that was unusual or somehow undesirable. So one of the things " + "I care a lot about is helping to remove that stigma, " + "to show girls that you can be feminine, you can like the things " + "that girls like, but you can also be really good at technology. " + "You can be really good at building things." + " - Marissa Meyer, Newsweek, 2010-12-22" "\n", + + "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg" + "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu" + "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg" + "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo" + "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp" + "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs" + "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy" + "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll" + "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" }, + + { "Typical first year for a new cluster: " + "~0.5 overheating " + "~1 PDU failure " + "~1 rack-move " + "~1 network rewiring " + "~20 rack failures " + "~5 racks go wonky " + "~8 network maintenances " + "~12 router reloads " + "~3 router failures " + "~dozens of minor 30-second blips for dns " + "~1000 individual machine failures " + "~thousands of hard drive failures " + "slow disks, bad memory, misconfigured machines, flaky machines, etc." + " - Jeff Dean, The Joys of Real Hardware" "\n", + + "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92" + "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3" + "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv" + "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk" + "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv" + "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp" + "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg" + "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs" + "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS" + "ZWFsIEhhcmR3YXJlCg" }, + + { "I'm the head of the webspam team at Google. " + "That means that if you type your name into Google and get porn back, " + "it's my fault. Unless you're a porn star, in which case porn is a " + "completely reasonable response." + " - Matt Cutts, Google Plus" "\n", + + "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg" + "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv" + "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz" + "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg" + "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs" + "IEdvb2dsZSBQbHVzCg" }, + + { "It will still be a long time before machines approach human " + "intelligence. " + "But luckily, machines don't actually have to be intelligent; " + "they just have to fake it. Access to a wealth of information, " + "combined with a rudimentary decision-making capacity, " + "can often be almost as useful. Of course, the results are better yet " + "when coupled with intelligence. A reference librarian with access to " + "a good search engine is a formidable tool." + " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" + "\n", + + "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg" + "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj" + "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg" + "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo" + "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg" + "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0" + "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy" + "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl" + "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu" + "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp" + "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw" + "NAo" }, + + // Degenerate edge case + { "", + "" }, + }}; + + return testcase; +} + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ + +#endif // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/memutil.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/memutil.cc index 0ba6574fdb..759222d19a 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/memutil.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/memutil.cc @@ -1,112 +1,112 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/memutil.h" - -#include <cstdlib> - + +#include <cstdlib> + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -int memcasecmp(const char* s1, const char* s2, size_t len) { - const unsigned char* us1 = reinterpret_cast<const unsigned char*>(s1); - const unsigned char* us2 = reinterpret_cast<const unsigned char*>(s2); - - for (size_t i = 0; i < len; i++) { - const int diff = +namespace strings_internal { + +int memcasecmp(const char* s1, const char* s2, size_t len) { + const unsigned char* us1 = reinterpret_cast<const unsigned char*>(s1); + const unsigned char* us2 = reinterpret_cast<const unsigned char*>(s2); + + for (size_t i = 0; i < len; i++) { + const int diff = int{static_cast<unsigned char>(y_absl::ascii_tolower(us1[i]))} - int{static_cast<unsigned char>(y_absl::ascii_tolower(us2[i]))}; - if (diff != 0) return diff; - } - return 0; -} - -char* memdup(const char* s, size_t slen) { - void* copy; - if ((copy = malloc(slen)) == nullptr) return nullptr; - memcpy(copy, s, slen); - return reinterpret_cast<char*>(copy); -} - -char* memrchr(const char* s, int c, size_t slen) { - for (const char* e = s + slen - 1; e >= s; e--) { - if (*e == c) return const_cast<char*>(e); - } - return nullptr; -} - -size_t memspn(const char* s, size_t slen, const char* accept) { - const char* p = s; - const char* spanp; - char c, sc; - -cont: - c = *p++; - if (slen-- == 0) return p - 1 - s; - for (spanp = accept; (sc = *spanp++) != '\0';) - if (sc == c) goto cont; - return p - 1 - s; -} - -size_t memcspn(const char* s, size_t slen, const char* reject) { - const char* p = s; - const char* spanp; - char c, sc; - - while (slen-- != 0) { - c = *p++; - for (spanp = reject; (sc = *spanp++) != '\0';) - if (sc == c) return p - 1 - s; - } - return p - s; -} - -char* mempbrk(const char* s, size_t slen, const char* accept) { - const char* scanp; - int sc; - - for (; slen; ++s, --slen) { - for (scanp = accept; (sc = *scanp++) != '\0';) - if (sc == *s) return const_cast<char*>(s); - } - return nullptr; -} - -// This is significantly faster for case-sensitive matches with very -// few possible matches. See unit test for benchmarks. -const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, - size_t neelen) { - if (0 == neelen) { - return phaystack; // even if haylen is 0 - } - if (haylen < neelen) return nullptr; - - const char* match; - const char* hayend = phaystack + haylen - neelen + 1; - // A static cast is used here to work around the fact that memchr returns - // a void* on Posix-compliant systems and const void* on Windows. - while ((match = static_cast<const char*>( - memchr(phaystack, pneedle[0], hayend - phaystack)))) { - if (memcmp(match, pneedle, neelen) == 0) - return match; - else - phaystack = match + 1; - } - return nullptr; -} - -} // namespace strings_internal + if (diff != 0) return diff; + } + return 0; +} + +char* memdup(const char* s, size_t slen) { + void* copy; + if ((copy = malloc(slen)) == nullptr) return nullptr; + memcpy(copy, s, slen); + return reinterpret_cast<char*>(copy); +} + +char* memrchr(const char* s, int c, size_t slen) { + for (const char* e = s + slen - 1; e >= s; e--) { + if (*e == c) return const_cast<char*>(e); + } + return nullptr; +} + +size_t memspn(const char* s, size_t slen, const char* accept) { + const char* p = s; + const char* spanp; + char c, sc; + +cont: + c = *p++; + if (slen-- == 0) return p - 1 - s; + for (spanp = accept; (sc = *spanp++) != '\0';) + if (sc == c) goto cont; + return p - 1 - s; +} + +size_t memcspn(const char* s, size_t slen, const char* reject) { + const char* p = s; + const char* spanp; + char c, sc; + + while (slen-- != 0) { + c = *p++; + for (spanp = reject; (sc = *spanp++) != '\0';) + if (sc == c) return p - 1 - s; + } + return p - s; +} + +char* mempbrk(const char* s, size_t slen, const char* accept) { + const char* scanp; + int sc; + + for (; slen; ++s, --slen) { + for (scanp = accept; (sc = *scanp++) != '\0';) + if (sc == *s) return const_cast<char*>(s); + } + return nullptr; +} + +// This is significantly faster for case-sensitive matches with very +// few possible matches. See unit test for benchmarks. +const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, + size_t neelen) { + if (0 == neelen) { + return phaystack; // even if haylen is 0 + } + if (haylen < neelen) return nullptr; + + const char* match; + const char* hayend = phaystack + haylen - neelen + 1; + // A static cast is used here to work around the fact that memchr returns + // a void* on Posix-compliant systems and const void* on Windows. + while ((match = static_cast<const char*>( + memchr(phaystack, pneedle[0], hayend - phaystack)))) { + if (memcmp(match, pneedle, neelen) == 0) + return match; + else + phaystack = match + 1; + } + return nullptr; +} + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/memutil.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/memutil.h index ee442fe25f..e4fbbdfac6 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/memutil.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/memutil.h @@ -1,148 +1,148 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// These routines provide mem versions of standard C string routines, -// such as strpbrk. They function exactly the same as the str versions, -// so if you wonder what they are, replace the word "mem" by -// "str" and check out the man page. I could return void*, as the -// strutil.h mem*() routines tend to do, but I return char* instead -// since this is by far the most common way these functions are called. -// -// The difference between the mem and str versions is the mem version -// takes a pointer and a length, rather than a '\0'-terminated string. -// The memcase* routines defined here assume the locale is "C" +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// These routines provide mem versions of standard C string routines, +// such as strpbrk. They function exactly the same as the str versions, +// so if you wonder what they are, replace the word "mem" by +// "str" and check out the man page. I could return void*, as the +// strutil.h mem*() routines tend to do, but I return char* instead +// since this is by far the most common way these functions are called. +// +// The difference between the mem and str versions is the mem version +// takes a pointer and a length, rather than a '\0'-terminated string. +// The memcase* routines defined here assume the locale is "C" // (they use y_absl::ascii_tolower instead of tolower). -// -// These routines are based on the BSD library. -// -// Here's a list of routines from string.h, and their mem analogues. -// Functions in lowercase are defined in string.h; those in UPPERCASE -// are defined here: -// -// strlen -- -// strcat strncat MEMCAT -// strcpy strncpy memcpy -// -- memccpy (very cool function, btw) -// -- memmove -// -- memset -// strcmp strncmp memcmp -// strcasecmp strncasecmp MEMCASECMP -// strchr memchr -// strcoll -- -// strxfrm -- -// strdup strndup MEMDUP -// strrchr MEMRCHR -// strspn MEMSPN -// strcspn MEMCSPN -// strpbrk MEMPBRK -// strstr MEMSTR MEMMEM -// (g)strcasestr MEMCASESTR MEMCASEMEM -// strtok -- -// strprefix MEMPREFIX (strprefix is from strutil.h) -// strcaseprefix MEMCASEPREFIX (strcaseprefix is from strutil.h) -// strsuffix MEMSUFFIX (strsuffix is from strutil.h) -// strcasesuffix MEMCASESUFFIX (strcasesuffix is from strutil.h) -// -- MEMIS -// -- MEMCASEIS -// strcount MEMCOUNT (strcount is from strutil.h) - -#ifndef ABSL_STRINGS_INTERNAL_MEMUTIL_H_ -#define ABSL_STRINGS_INTERNAL_MEMUTIL_H_ - -#include <cstddef> -#include <cstring> - +// +// These routines are based on the BSD library. +// +// Here's a list of routines from string.h, and their mem analogues. +// Functions in lowercase are defined in string.h; those in UPPERCASE +// are defined here: +// +// strlen -- +// strcat strncat MEMCAT +// strcpy strncpy memcpy +// -- memccpy (very cool function, btw) +// -- memmove +// -- memset +// strcmp strncmp memcmp +// strcasecmp strncasecmp MEMCASECMP +// strchr memchr +// strcoll -- +// strxfrm -- +// strdup strndup MEMDUP +// strrchr MEMRCHR +// strspn MEMSPN +// strcspn MEMCSPN +// strpbrk MEMPBRK +// strstr MEMSTR MEMMEM +// (g)strcasestr MEMCASESTR MEMCASEMEM +// strtok -- +// strprefix MEMPREFIX (strprefix is from strutil.h) +// strcaseprefix MEMCASEPREFIX (strcaseprefix is from strutil.h) +// strsuffix MEMSUFFIX (strsuffix is from strutil.h) +// strcasesuffix MEMCASESUFFIX (strcasesuffix is from strutil.h) +// -- MEMIS +// -- MEMCASEIS +// strcount MEMCOUNT (strcount is from strutil.h) + +#ifndef ABSL_STRINGS_INTERNAL_MEMUTIL_H_ +#define ABSL_STRINGS_INTERNAL_MEMUTIL_H_ + +#include <cstddef> +#include <cstring> + #include "y_absl/base/port.h" // disable some warnings on Windows #include "y_absl/strings/ascii.h" // for y_absl::ascii_tolower - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -inline char* memcat(char* dest, size_t destlen, const char* src, - size_t srclen) { - return reinterpret_cast<char*>(memcpy(dest + destlen, src, srclen)); -} - -int memcasecmp(const char* s1, const char* s2, size_t len); -char* memdup(const char* s, size_t slen); -char* memrchr(const char* s, int c, size_t slen); -size_t memspn(const char* s, size_t slen, const char* accept); -size_t memcspn(const char* s, size_t slen, const char* reject); -char* mempbrk(const char* s, size_t slen, const char* accept); - -// This is for internal use only. Don't call this directly -template <bool case_sensitive> -const char* int_memmatch(const char* haystack, size_t haylen, - const char* needle, size_t neelen) { - if (0 == neelen) { - return haystack; // even if haylen is 0 - } - const char* hayend = haystack + haylen; - const char* needlestart = needle; - const char* needleend = needlestart + neelen; - - for (; haystack < hayend; ++haystack) { - char hay = case_sensitive - ? *haystack +namespace strings_internal { + +inline char* memcat(char* dest, size_t destlen, const char* src, + size_t srclen) { + return reinterpret_cast<char*>(memcpy(dest + destlen, src, srclen)); +} + +int memcasecmp(const char* s1, const char* s2, size_t len); +char* memdup(const char* s, size_t slen); +char* memrchr(const char* s, int c, size_t slen); +size_t memspn(const char* s, size_t slen, const char* accept); +size_t memcspn(const char* s, size_t slen, const char* reject); +char* mempbrk(const char* s, size_t slen, const char* accept); + +// This is for internal use only. Don't call this directly +template <bool case_sensitive> +const char* int_memmatch(const char* haystack, size_t haylen, + const char* needle, size_t neelen) { + if (0 == neelen) { + return haystack; // even if haylen is 0 + } + const char* hayend = haystack + haylen; + const char* needlestart = needle; + const char* needleend = needlestart + neelen; + + for (; haystack < hayend; ++haystack) { + char hay = case_sensitive + ? *haystack : y_absl::ascii_tolower(static_cast<unsigned char>(*haystack)); - char nee = case_sensitive - ? *needle + char nee = case_sensitive + ? *needle : y_absl::ascii_tolower(static_cast<unsigned char>(*needle)); - if (hay == nee) { - if (++needle == needleend) { - return haystack + 1 - neelen; - } - } else if (needle != needlestart) { - // must back up haystack in case a prefix matched (find "aab" in "aaab") - haystack -= needle - needlestart; // for loop will advance one more - needle = needlestart; - } - } - return nullptr; -} - -// These are the guys you can call directly -inline const char* memstr(const char* phaystack, size_t haylen, - const char* pneedle) { - return int_memmatch<true>(phaystack, haylen, pneedle, strlen(pneedle)); -} - -inline const char* memcasestr(const char* phaystack, size_t haylen, - const char* pneedle) { - return int_memmatch<false>(phaystack, haylen, pneedle, strlen(pneedle)); -} - -inline const char* memmem(const char* phaystack, size_t haylen, - const char* pneedle, size_t needlelen) { - return int_memmatch<true>(phaystack, haylen, pneedle, needlelen); -} - -inline const char* memcasemem(const char* phaystack, size_t haylen, - const char* pneedle, size_t needlelen) { - return int_memmatch<false>(phaystack, haylen, pneedle, needlelen); -} - -// This is significantly faster for case-sensitive matches with very -// few possible matches. See unit test for benchmarks. -const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, - size_t neelen); - -} // namespace strings_internal + if (hay == nee) { + if (++needle == needleend) { + return haystack + 1 - neelen; + } + } else if (needle != needlestart) { + // must back up haystack in case a prefix matched (find "aab" in "aaab") + haystack -= needle - needlestart; // for loop will advance one more + needle = needlestart; + } + } + return nullptr; +} + +// These are the guys you can call directly +inline const char* memstr(const char* phaystack, size_t haylen, + const char* pneedle) { + return int_memmatch<true>(phaystack, haylen, pneedle, strlen(pneedle)); +} + +inline const char* memcasestr(const char* phaystack, size_t haylen, + const char* pneedle) { + return int_memmatch<false>(phaystack, haylen, pneedle, strlen(pneedle)); +} + +inline const char* memmem(const char* phaystack, size_t haylen, + const char* pneedle, size_t needlelen) { + return int_memmatch<true>(phaystack, haylen, pneedle, needlelen); +} + +inline const char* memcasemem(const char* phaystack, size_t haylen, + const char* pneedle, size_t needlelen) { + return int_memmatch<false>(phaystack, haylen, pneedle, needlelen); +} + +// This is significantly faster for case-sensitive matches with very +// few possible matches. See unit test for benchmarks. +const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, + size_t neelen); + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_MEMUTIL_H_ + +#endif // ABSL_STRINGS_INTERNAL_MEMUTIL_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h index 12aec3ac11..bfae683bf6 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h @@ -1,184 +1,184 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file contains common things needed by numbers_test.cc, -// numbers_legacy_test.cc and numbers_benchmark.cc. - -#ifndef ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ -#define ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ - -#include <array> -#include <cstdint> -#include <limits> +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file contains common things needed by numbers_test.cc, +// numbers_legacy_test.cc and numbers_benchmark.cc. + +#ifndef ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ +#define ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ + +#include <array> +#include <cstdint> +#include <limits> #include <util/generic/string.h> - + #include "y_absl/base/config.h" namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -template <typename IntType> +namespace strings_internal { + +template <typename IntType> inline bool Itoa(IntType value, int base, TString* destination) { - destination->clear(); - if (base <= 1 || base > 36) { - return false; - } - - if (value == 0) { - destination->push_back('0'); - return true; - } - - bool negative = value < 0; - while (value != 0) { - const IntType next_value = value / base; - // Can't use std::abs here because of problems when IntType is unsigned. - int remainder = - static_cast<int>(value > next_value * base ? value - next_value * base - : next_value * base - value); - char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10; - destination->insert(0, 1, c); - value = next_value; - } - - if (negative) { - destination->insert(0, 1, '-'); - } - return true; -} - -struct uint32_test_case { - const char* str; - bool expect_ok; - int base; // base to pass to the conversion function - uint32_t expected; -}; - -inline const std::array<uint32_test_case, 27>& strtouint32_test_cases() { - static const std::array<uint32_test_case, 27> test_cases{{ - {"0xffffffff", true, 16, (std::numeric_limits<uint32_t>::max)()}, - {"0x34234324", true, 16, 0x34234324}, - {"34234324", true, 16, 0x34234324}, - {"0", true, 16, 0}, - {" \t\n 0xffffffff", true, 16, (std::numeric_limits<uint32_t>::max)()}, - {" \f\v 46", true, 10, 46}, // must accept weird whitespace - {" \t\n 72717222", true, 8, 072717222}, - {" \t\n 072717222", true, 8, 072717222}, - {" \t\n 072717228", false, 8, 07271722}, - {"0", true, 0, 0}, - - // Base-10 version. - {"34234324", true, 0, 34234324}, - {"4294967295", true, 0, (std::numeric_limits<uint32_t>::max)()}, - {"34234324 \n\t", true, 10, 34234324}, - - // Unusual base - {"0", true, 3, 0}, - {"2", true, 3, 2}, - {"11", true, 3, 4}, - - // Invalid uints. - {"", false, 0, 0}, - {" ", false, 0, 0}, - {"abc", false, 0, 0}, // would be valid hex, but prefix is missing - {"34234324a", false, 0, 34234324}, - {"34234.3", false, 0, 34234}, - {"-1", false, 0, 0}, - {" -123", false, 0, 0}, - {" \t\n -123", false, 0, 0}, - - // Out of bounds. - {"4294967296", false, 0, (std::numeric_limits<uint32_t>::max)()}, - {"0x100000000", false, 0, (std::numeric_limits<uint32_t>::max)()}, - {nullptr, false, 0, 0}, - }}; - return test_cases; -} - -struct uint64_test_case { - const char* str; - bool expect_ok; - int base; - uint64_t expected; -}; - -inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() { - static const std::array<uint64_test_case, 34> test_cases{{ - {"0x3423432448783446", true, 16, int64_t{0x3423432448783446}}, - {"3423432448783446", true, 16, int64_t{0x3423432448783446}}, - - {"0", true, 16, 0}, - {"000", true, 0, 0}, - {"0", true, 0, 0}, - {" \t\n 0xffffffffffffffff", true, 16, - (std::numeric_limits<uint64_t>::max)()}, - - {"012345670123456701234", true, 8, int64_t{012345670123456701234}}, - {"12345670123456701234", true, 8, int64_t{012345670123456701234}}, - - {"12845670123456701234", false, 8, 0}, - - // Base-10 version. - {"34234324487834466", true, 0, int64_t{34234324487834466}}, - - {" \t\n 18446744073709551615", true, 0, - (std::numeric_limits<uint64_t>::max)()}, - - {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}}, - - {" \f\v 46", true, 10, 46}, // must accept weird whitespace - - // Unusual base - {"0", true, 3, 0}, - {"2", true, 3, 2}, - {"11", true, 3, 4}, - - {"0", true, 0, 0}, - - // Invalid uints. - {"", false, 0, 0}, - {" ", false, 0, 0}, - {"abc", false, 0, 0}, - {"34234324487834466a", false, 0, 0}, - {"34234487834466.3", false, 0, 0}, - {"-1", false, 0, 0}, - {" -123", false, 0, 0}, - {" \t\n -123", false, 0, 0}, - - // Out of bounds. - {"18446744073709551616", false, 10, 0}, - {"18446744073709551616", false, 0, 0}, - {"0x10000000000000000", false, 16, - (std::numeric_limits<uint64_t>::max)()}, - {"0X10000000000000000", false, 16, - (std::numeric_limits<uint64_t>::max)()}, // 0X versus 0x. - {"0x10000000000000000", false, 0, (std::numeric_limits<uint64_t>::max)()}, - {"0X10000000000000000", false, 0, - (std::numeric_limits<uint64_t>::max)()}, // 0X versus 0x. - - {"0x1234", true, 16, 0x1234}, - + destination->clear(); + if (base <= 1 || base > 36) { + return false; + } + + if (value == 0) { + destination->push_back('0'); + return true; + } + + bool negative = value < 0; + while (value != 0) { + const IntType next_value = value / base; + // Can't use std::abs here because of problems when IntType is unsigned. + int remainder = + static_cast<int>(value > next_value * base ? value - next_value * base + : next_value * base - value); + char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10; + destination->insert(0, 1, c); + value = next_value; + } + + if (negative) { + destination->insert(0, 1, '-'); + } + return true; +} + +struct uint32_test_case { + const char* str; + bool expect_ok; + int base; // base to pass to the conversion function + uint32_t expected; +}; + +inline const std::array<uint32_test_case, 27>& strtouint32_test_cases() { + static const std::array<uint32_test_case, 27> test_cases{{ + {"0xffffffff", true, 16, (std::numeric_limits<uint32_t>::max)()}, + {"0x34234324", true, 16, 0x34234324}, + {"34234324", true, 16, 0x34234324}, + {"0", true, 16, 0}, + {" \t\n 0xffffffff", true, 16, (std::numeric_limits<uint32_t>::max)()}, + {" \f\v 46", true, 10, 46}, // must accept weird whitespace + {" \t\n 72717222", true, 8, 072717222}, + {" \t\n 072717222", true, 8, 072717222}, + {" \t\n 072717228", false, 8, 07271722}, + {"0", true, 0, 0}, + + // Base-10 version. + {"34234324", true, 0, 34234324}, + {"4294967295", true, 0, (std::numeric_limits<uint32_t>::max)()}, + {"34234324 \n\t", true, 10, 34234324}, + + // Unusual base + {"0", true, 3, 0}, + {"2", true, 3, 2}, + {"11", true, 3, 4}, + + // Invalid uints. + {"", false, 0, 0}, + {" ", false, 0, 0}, + {"abc", false, 0, 0}, // would be valid hex, but prefix is missing + {"34234324a", false, 0, 34234324}, + {"34234.3", false, 0, 34234}, + {"-1", false, 0, 0}, + {" -123", false, 0, 0}, + {" \t\n -123", false, 0, 0}, + + // Out of bounds. + {"4294967296", false, 0, (std::numeric_limits<uint32_t>::max)()}, + {"0x100000000", false, 0, (std::numeric_limits<uint32_t>::max)()}, + {nullptr, false, 0, 0}, + }}; + return test_cases; +} + +struct uint64_test_case { + const char* str; + bool expect_ok; + int base; + uint64_t expected; +}; + +inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() { + static const std::array<uint64_test_case, 34> test_cases{{ + {"0x3423432448783446", true, 16, int64_t{0x3423432448783446}}, + {"3423432448783446", true, 16, int64_t{0x3423432448783446}}, + + {"0", true, 16, 0}, + {"000", true, 0, 0}, + {"0", true, 0, 0}, + {" \t\n 0xffffffffffffffff", true, 16, + (std::numeric_limits<uint64_t>::max)()}, + + {"012345670123456701234", true, 8, int64_t{012345670123456701234}}, + {"12345670123456701234", true, 8, int64_t{012345670123456701234}}, + + {"12845670123456701234", false, 8, 0}, + + // Base-10 version. + {"34234324487834466", true, 0, int64_t{34234324487834466}}, + + {" \t\n 18446744073709551615", true, 0, + (std::numeric_limits<uint64_t>::max)()}, + + {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}}, + + {" \f\v 46", true, 10, 46}, // must accept weird whitespace + + // Unusual base + {"0", true, 3, 0}, + {"2", true, 3, 2}, + {"11", true, 3, 4}, + + {"0", true, 0, 0}, + + // Invalid uints. + {"", false, 0, 0}, + {" ", false, 0, 0}, + {"abc", false, 0, 0}, + {"34234324487834466a", false, 0, 0}, + {"34234487834466.3", false, 0, 0}, + {"-1", false, 0, 0}, + {" -123", false, 0, 0}, + {" \t\n -123", false, 0, 0}, + + // Out of bounds. + {"18446744073709551616", false, 10, 0}, + {"18446744073709551616", false, 0, 0}, + {"0x10000000000000000", false, 16, + (std::numeric_limits<uint64_t>::max)()}, + {"0X10000000000000000", false, 16, + (std::numeric_limits<uint64_t>::max)()}, // 0X versus 0x. + {"0x10000000000000000", false, 0, (std::numeric_limits<uint64_t>::max)()}, + {"0X10000000000000000", false, 0, + (std::numeric_limits<uint64_t>::max)()}, // 0X versus 0x. + + {"0x1234", true, 16, 0x1234}, + // Base-10 string version. - {"1234", true, 0, 1234}, - {nullptr, false, 0, 0}, - }}; - return test_cases; -} - -} // namespace strings_internal + {"1234", true, 0, 1234}, + {nullptr, false, 0, 0}, + }}; + return test_cases; +} + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ + +#endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/ostringstream.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/ostringstream.cc index ba18857d83..318cfc1f05 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/ostringstream.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/ostringstream.cc @@ -1,36 +1,36 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/ostringstream.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -OStringStream::Buf::int_type OStringStream::overflow(int c) { - assert(s_); - if (!Buf::traits_type::eq_int_type(c, Buf::traits_type::eof())) - s_->push_back(static_cast<char>(c)); - return 1; -} - -std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) { - assert(s_); - s_->append(s, n); - return n; -} - -} // namespace strings_internal +namespace strings_internal { + +OStringStream::Buf::int_type OStringStream::overflow(int c) { + assert(s_); + if (!Buf::traits_type::eq_int_type(c, Buf::traits_type::eof())) + s_->push_back(static_cast<char>(c)); + return 1; +} + +std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) { + assert(s_); + s_->append(s, n); + return n; +} + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/ostringstream.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/ostringstream.h index d00cef9c23..3a8886405a 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/ostringstream.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/ostringstream.h @@ -1,89 +1,89 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ -#define ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ - -#include <cassert> -#include <ostream> -#include <streambuf> +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ +#define ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ + +#include <cassert> +#include <ostream> +#include <streambuf> #include <util/generic/string.h> - + #include "y_absl/base/port.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - +namespace strings_internal { + // The same as std::ostringstream but appends to a user-specified TString, -// and is faster. It is ~70% faster to create, ~50% faster to write to, and +// and is faster. It is ~70% faster to create, ~50% faster to write to, and // completely free to extract the result TString. -// +// // TString s; -// OStringStream strm(&s); -// strm << 42 << ' ' << 3.14; // appends to `s` -// -// The stream object doesn't have to be named. Starting from C++11 operator<< -// works with rvalues of std::ostream. -// +// OStringStream strm(&s); +// strm << 42 << ' ' << 3.14; // appends to `s` +// +// The stream object doesn't have to be named. Starting from C++11 operator<< +// works with rvalues of std::ostream. +// // TString s; -// OStringStream(&s) << 42 << ' ' << 3.14; // appends to `s` -// -// OStringStream is faster to create than std::ostringstream but it's still -// relatively slow. Avoid creating multiple streams where a single stream will -// do. -// -// Creates unnecessary instances of OStringStream: slow. -// +// OStringStream(&s) << 42 << ' ' << 3.14; // appends to `s` +// +// OStringStream is faster to create than std::ostringstream but it's still +// relatively slow. Avoid creating multiple streams where a single stream will +// do. +// +// Creates unnecessary instances of OStringStream: slow. +// // TString s; -// OStringStream(&s) << 42; -// OStringStream(&s) << ' '; -// OStringStream(&s) << 3.14; -// -// Creates a single instance of OStringStream and reuses it: fast. -// +// OStringStream(&s) << 42; +// OStringStream(&s) << ' '; +// OStringStream(&s) << 3.14; +// +// Creates a single instance of OStringStream and reuses it: fast. +// // TString s; -// OStringStream strm(&s); -// strm << 42; -// strm << ' '; -// strm << 3.14; -// -// Note: flush() has no effect. No reason to call it. -class OStringStream : private std::basic_streambuf<char>, public std::ostream { - public: - // The argument can be null, in which case you'll need to call str(p) with a - // non-null argument before you can write to the stream. - // +// OStringStream strm(&s); +// strm << 42; +// strm << ' '; +// strm << 3.14; +// +// Note: flush() has no effect. No reason to call it. +class OStringStream : private std::basic_streambuf<char>, public std::ostream { + public: + // The argument can be null, in which case you'll need to call str(p) with a + // non-null argument before you can write to the stream. + // // The destructor of OStringStream doesn't use the TString. It's OK to // destroy the TString before the stream. explicit OStringStream(TString* s) : std::ostream(this), s_(s) {} - + TString* str() { return s_; } const TString* str() const { return s_; } void str(TString* s) { s_ = s; } - - private: - using Buf = std::basic_streambuf<char>; - - Buf::int_type overflow(int c) override; - std::streamsize xsputn(const char* s, std::streamsize n) override; - + + private: + using Buf = std::basic_streambuf<char>; + + Buf::int_type overflow(int c) override; + std::streamsize xsputn(const char* s, std::streamsize n) override; + TString* s_; -}; - -} // namespace strings_internal +}; + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ + +#endif // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/pow10_helper.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/pow10_helper.h index e4d41d7e4e..7cebbdaeeb 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/pow10_helper.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/pow10_helper.h @@ -1,40 +1,40 @@ -// -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This test helper library contains a table of powers of 10, to guarantee -// precise values are computed across the full range of doubles. We can't rely -// on the pow() function, because not all standard libraries ship a version -// that is precise. -#ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ -#define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ - -#include <vector> - +// +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This test helper library contains a table of powers of 10, to guarantee +// precise values are computed across the full range of doubles. We can't rely +// on the pow() function, because not all standard libraries ship a version +// that is precise. +#ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ +#define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ + +#include <vector> + #include "y_absl/base/config.h" namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -// Computes the precise value of 10^exp. (I.e. the nearest representable -// double to the exact value, rounding to nearest-even in the (single) case of -// being exactly halfway between.) -double Pow10(int exp); - -} // namespace strings_internal +namespace strings_internal { + +// Computes the precise value of 10^exp. (I.e. the nearest representable +// double to the exact value, rounding to nearest-even in the (single) case of +// being exactly halfway between.) +double Pow10(int exp); + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ + +#endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/resize_uninitialized.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/resize_uninitialized.h index 14860bb237..0c3af713f8 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/resize_uninitialized.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/resize_uninitialized.h @@ -1,73 +1,73 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#ifndef ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ -#define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ - +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ +#define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ + #include <algorithm> #include <util/generic/string.h> -#include <type_traits> -#include <utility> - +#include <type_traits> +#include <utility> + #include "y_absl/base/port.h" #include "y_absl/meta/type_traits.h" // for void_t - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - +namespace strings_internal { + // In this type trait, we look for a __resize_default_init member function, and // we use it if available, otherwise, we use resize. We provide HasMember to // indicate whether __resize_default_init is present. -template <typename string_type, typename = void> -struct ResizeUninitializedTraits { - using HasMember = std::false_type; - static void Resize(string_type* s, size_t new_size) { s->resize(new_size); } -}; - -// __resize_default_init is provided by libc++ >= 8.0 -template <typename string_type> -struct ResizeUninitializedTraits< +template <typename string_type, typename = void> +struct ResizeUninitializedTraits { + using HasMember = std::false_type; + static void Resize(string_type* s, size_t new_size) { s->resize(new_size); } +}; + +// __resize_default_init is provided by libc++ >= 8.0 +template <typename string_type> +struct ResizeUninitializedTraits< string_type, y_absl::void_t<decltype(std::declval<string_type&>() - .__resize_default_init(237))> > { - using HasMember = std::true_type; - static void Resize(string_type* s, size_t new_size) { - s->__resize_default_init(new_size); - } -}; - + .__resize_default_init(237))> > { + using HasMember = std::true_type; + static void Resize(string_type* s, size_t new_size) { + s->__resize_default_init(new_size); + } +}; + // Returns true if the TString implementation supports a resize where // the new characters added to the TString are left untouched. -// -// (A better name might be "STLStringSupportsUninitializedResize", alluding to -// the previous function.) -template <typename string_type> -inline constexpr bool STLStringSupportsNontrashingResize(string_type*) { - return ResizeUninitializedTraits<string_type>::HasMember::value; -} - -// Like str->resize(new_size), except any new characters added to "*str" as a -// result of resizing may be left uninitialized, rather than being filled with -// '0' bytes. Typically used when code is then going to overwrite the backing +// +// (A better name might be "STLStringSupportsUninitializedResize", alluding to +// the previous function.) +template <typename string_type> +inline constexpr bool STLStringSupportsNontrashingResize(string_type*) { + return ResizeUninitializedTraits<string_type>::HasMember::value; +} + +// Like str->resize(new_size), except any new characters added to "*str" as a +// result of resizing may be left uninitialized, rather than being filled with +// '0' bytes. Typically used when code is then going to overwrite the backing // store of the TString with known data. -template <typename string_type, typename = void> -inline void STLStringResizeUninitialized(string_type* s, size_t new_size) { - ResizeUninitializedTraits<string_type>::Resize(s, new_size); -} - +template <typename string_type, typename = void> +inline void STLStringResizeUninitialized(string_type* s, size_t new_size) { + ResizeUninitializedTraits<string_type>::Resize(s, new_size); +} + // Used to ensure exponential growth so that the amortized complexity of // increasing the string size by a small amount is O(1), in contrast to // O(str->size()) in the case of precise growth. @@ -112,8 +112,8 @@ void STLStringResizeUninitializedAmortized(string_type* s, size_t new_size) { } } -} // namespace strings_internal +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ + +#endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/stl_type_traits.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/stl_type_traits.h index db8d4635d0..ed7a191fc0 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/stl_type_traits.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/stl_type_traits.h @@ -1,248 +1,248 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// Thie file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type -// trait metafunction to assist in working with the _GLIBCXX_DEBUG debug -// wrappers of STL containers. -// -// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Thie file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type +// trait metafunction to assist in working with the _GLIBCXX_DEBUG debug +// wrappers of STL containers. +// +// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including // y_absl/strings/str_split.h. -// +// // IWYU pragma: private, include "y_absl/strings/str_split.h" - -#ifndef ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ -#define ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ - -#include <array> -#include <bitset> -#include <deque> -#include <forward_list> -#include <list> -#include <map> -#include <set> -#include <type_traits> -#include <unordered_map> -#include <unordered_set> -#include <vector> - + +#ifndef ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ +#define ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ + +#include <array> +#include <bitset> +#include <deque> +#include <forward_list> +#include <list> +#include <map> +#include <set> +#include <type_traits> +#include <unordered_map> +#include <unordered_set> +#include <vector> + #include "y_absl/meta/type_traits.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -template <typename C, template <typename...> class T> -struct IsSpecializationImpl : std::false_type {}; -template <template <typename...> class T, typename... Args> -struct IsSpecializationImpl<T<Args...>, T> : std::true_type {}; -template <typename C, template <typename...> class T> +namespace strings_internal { + +template <typename C, template <typename...> class T> +struct IsSpecializationImpl : std::false_type {}; +template <template <typename...> class T, typename... Args> +struct IsSpecializationImpl<T<Args...>, T> : std::true_type {}; +template <typename C, template <typename...> class T> using IsSpecialization = IsSpecializationImpl<y_absl::decay_t<C>, T>; - -template <typename C> -struct IsArrayImpl : std::false_type {}; -template <template <typename, size_t> class A, typename T, size_t N> -struct IsArrayImpl<A<T, N>> : std::is_same<A<T, N>, std::array<T, N>> {}; -template <typename C> + +template <typename C> +struct IsArrayImpl : std::false_type {}; +template <template <typename, size_t> class A, typename T, size_t N> +struct IsArrayImpl<A<T, N>> : std::is_same<A<T, N>, std::array<T, N>> {}; +template <typename C> using IsArray = IsArrayImpl<y_absl::decay_t<C>>; - -template <typename C> -struct IsBitsetImpl : std::false_type {}; -template <template <size_t> class B, size_t N> -struct IsBitsetImpl<B<N>> : std::is_same<B<N>, std::bitset<N>> {}; -template <typename C> + +template <typename C> +struct IsBitsetImpl : std::false_type {}; +template <template <size_t> class B, size_t N> +struct IsBitsetImpl<B<N>> : std::is_same<B<N>, std::bitset<N>> {}; +template <typename C> using IsBitset = IsBitsetImpl<y_absl::decay_t<C>>; - -template <typename C> -struct IsSTLContainer + +template <typename C> +struct IsSTLContainer : y_absl::disjunction< - IsArray<C>, IsBitset<C>, IsSpecialization<C, std::deque>, - IsSpecialization<C, std::forward_list>, - IsSpecialization<C, std::list>, IsSpecialization<C, std::map>, - IsSpecialization<C, std::multimap>, IsSpecialization<C, std::set>, - IsSpecialization<C, std::multiset>, - IsSpecialization<C, std::unordered_map>, - IsSpecialization<C, std::unordered_multimap>, - IsSpecialization<C, std::unordered_set>, - IsSpecialization<C, std::unordered_multiset>, - IsSpecialization<C, std::vector>> {}; - -template <typename C, template <typename...> class T, typename = void> -struct IsBaseOfSpecializationImpl : std::false_type {}; -// IsBaseOfSpecializationImpl needs multiple partial specializations to SFINAE -// on the existence of container dependent types and plug them into the STL -// template. -template <typename C, template <typename, typename> class T> -struct IsBaseOfSpecializationImpl< + IsArray<C>, IsBitset<C>, IsSpecialization<C, std::deque>, + IsSpecialization<C, std::forward_list>, + IsSpecialization<C, std::list>, IsSpecialization<C, std::map>, + IsSpecialization<C, std::multimap>, IsSpecialization<C, std::set>, + IsSpecialization<C, std::multiset>, + IsSpecialization<C, std::unordered_map>, + IsSpecialization<C, std::unordered_multimap>, + IsSpecialization<C, std::unordered_set>, + IsSpecialization<C, std::unordered_multiset>, + IsSpecialization<C, std::vector>> {}; + +template <typename C, template <typename...> class T, typename = void> +struct IsBaseOfSpecializationImpl : std::false_type {}; +// IsBaseOfSpecializationImpl needs multiple partial specializations to SFINAE +// on the existence of container dependent types and plug them into the STL +// template. +template <typename C, template <typename, typename> class T> +struct IsBaseOfSpecializationImpl< C, T, y_absl::void_t<typename C::value_type, typename C::allocator_type>> - : std::is_base_of<C, - T<typename C::value_type, typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, + : std::is_base_of<C, + T<typename C::value_type, typename C::allocator_type>> {}; +template <typename C, template <typename, typename, typename> class T> +struct IsBaseOfSpecializationImpl< + C, T, y_absl::void_t<typename C::key_type, typename C::key_compare, - typename C::allocator_type>> - : std::is_base_of<C, T<typename C::key_type, typename C::key_compare, - typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, + typename C::allocator_type>> + : std::is_base_of<C, T<typename C::key_type, typename C::key_compare, + typename C::allocator_type>> {}; +template <typename C, template <typename, typename, typename, typename> class T> +struct IsBaseOfSpecializationImpl< + C, T, y_absl::void_t<typename C::key_type, typename C::mapped_type, - typename C::key_compare, typename C::allocator_type>> - : std::is_base_of<C, - T<typename C::key_type, typename C::mapped_type, - typename C::key_compare, typename C::allocator_type>> { -}; -template <typename C, template <typename, typename, typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, + typename C::key_compare, typename C::allocator_type>> + : std::is_base_of<C, + T<typename C::key_type, typename C::mapped_type, + typename C::key_compare, typename C::allocator_type>> { +}; +template <typename C, template <typename, typename, typename, typename> class T> +struct IsBaseOfSpecializationImpl< + C, T, y_absl::void_t<typename C::key_type, typename C::hasher, - typename C::key_equal, typename C::allocator_type>> - : std::is_base_of<C, T<typename C::key_type, typename C::hasher, - typename C::key_equal, typename C::allocator_type>> { -}; -template <typename C, - template <typename, typename, typename, typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, + typename C::key_equal, typename C::allocator_type>> + : std::is_base_of<C, T<typename C::key_type, typename C::hasher, + typename C::key_equal, typename C::allocator_type>> { +}; +template <typename C, + template <typename, typename, typename, typename, typename> class T> +struct IsBaseOfSpecializationImpl< + C, T, y_absl::void_t<typename C::key_type, typename C::mapped_type, - typename C::hasher, typename C::key_equal, - typename C::allocator_type>> - : std::is_base_of<C, T<typename C::key_type, typename C::mapped_type, - typename C::hasher, typename C::key_equal, - typename C::allocator_type>> {}; -template <typename C, template <typename...> class T> + typename C::hasher, typename C::key_equal, + typename C::allocator_type>> + : std::is_base_of<C, T<typename C::key_type, typename C::mapped_type, + typename C::hasher, typename C::key_equal, + typename C::allocator_type>> {}; +template <typename C, template <typename...> class T> using IsBaseOfSpecialization = IsBaseOfSpecializationImpl<y_absl::decay_t<C>, T>; - -template <typename C> -struct IsBaseOfArrayImpl : std::false_type {}; -template <template <typename, size_t> class A, typename T, size_t N> -struct IsBaseOfArrayImpl<A<T, N>> : std::is_base_of<A<T, N>, std::array<T, N>> { -}; -template <typename C> + +template <typename C> +struct IsBaseOfArrayImpl : std::false_type {}; +template <template <typename, size_t> class A, typename T, size_t N> +struct IsBaseOfArrayImpl<A<T, N>> : std::is_base_of<A<T, N>, std::array<T, N>> { +}; +template <typename C> using IsBaseOfArray = IsBaseOfArrayImpl<y_absl::decay_t<C>>; - -template <typename C> -struct IsBaseOfBitsetImpl : std::false_type {}; -template <template <size_t> class B, size_t N> -struct IsBaseOfBitsetImpl<B<N>> : std::is_base_of<B<N>, std::bitset<N>> {}; -template <typename C> + +template <typename C> +struct IsBaseOfBitsetImpl : std::false_type {}; +template <template <size_t> class B, size_t N> +struct IsBaseOfBitsetImpl<B<N>> : std::is_base_of<B<N>, std::bitset<N>> {}; +template <typename C> using IsBaseOfBitset = IsBaseOfBitsetImpl<y_absl::decay_t<C>>; - -template <typename C> -struct IsBaseOfSTLContainer + +template <typename C> +struct IsBaseOfSTLContainer : y_absl::disjunction<IsBaseOfArray<C>, IsBaseOfBitset<C>, - IsBaseOfSpecialization<C, std::deque>, - IsBaseOfSpecialization<C, std::forward_list>, - IsBaseOfSpecialization<C, std::list>, - IsBaseOfSpecialization<C, std::map>, - IsBaseOfSpecialization<C, std::multimap>, - IsBaseOfSpecialization<C, std::set>, - IsBaseOfSpecialization<C, std::multiset>, - IsBaseOfSpecialization<C, std::unordered_map>, - IsBaseOfSpecialization<C, std::unordered_multimap>, - IsBaseOfSpecialization<C, std::unordered_set>, - IsBaseOfSpecialization<C, std::unordered_multiset>, - IsBaseOfSpecialization<C, std::vector>> {}; - -template <typename C, template <typename...> class T, typename = void> -struct IsConvertibleToSpecializationImpl : std::false_type {}; -// IsConvertibleToSpecializationImpl needs multiple partial specializations to -// SFINAE on the existence of container dependent types and plug them into the -// STL template. -template <typename C, template <typename, typename> class T> -struct IsConvertibleToSpecializationImpl< + IsBaseOfSpecialization<C, std::deque>, + IsBaseOfSpecialization<C, std::forward_list>, + IsBaseOfSpecialization<C, std::list>, + IsBaseOfSpecialization<C, std::map>, + IsBaseOfSpecialization<C, std::multimap>, + IsBaseOfSpecialization<C, std::set>, + IsBaseOfSpecialization<C, std::multiset>, + IsBaseOfSpecialization<C, std::unordered_map>, + IsBaseOfSpecialization<C, std::unordered_multimap>, + IsBaseOfSpecialization<C, std::unordered_set>, + IsBaseOfSpecialization<C, std::unordered_multiset>, + IsBaseOfSpecialization<C, std::vector>> {}; + +template <typename C, template <typename...> class T, typename = void> +struct IsConvertibleToSpecializationImpl : std::false_type {}; +// IsConvertibleToSpecializationImpl needs multiple partial specializations to +// SFINAE on the existence of container dependent types and plug them into the +// STL template. +template <typename C, template <typename, typename> class T> +struct IsConvertibleToSpecializationImpl< C, T, y_absl::void_t<typename C::value_type, typename C::allocator_type>> - : std::is_convertible< - C, T<typename C::value_type, typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, + : std::is_convertible< + C, T<typename C::value_type, typename C::allocator_type>> {}; +template <typename C, template <typename, typename, typename> class T> +struct IsConvertibleToSpecializationImpl< + C, T, y_absl::void_t<typename C::key_type, typename C::key_compare, - typename C::allocator_type>> - : std::is_convertible<C, T<typename C::key_type, typename C::key_compare, - typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, + typename C::allocator_type>> + : std::is_convertible<C, T<typename C::key_type, typename C::key_compare, + typename C::allocator_type>> {}; +template <typename C, template <typename, typename, typename, typename> class T> +struct IsConvertibleToSpecializationImpl< + C, T, y_absl::void_t<typename C::key_type, typename C::mapped_type, - typename C::key_compare, typename C::allocator_type>> - : std::is_convertible< - C, T<typename C::key_type, typename C::mapped_type, - typename C::key_compare, typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, + typename C::key_compare, typename C::allocator_type>> + : std::is_convertible< + C, T<typename C::key_type, typename C::mapped_type, + typename C::key_compare, typename C::allocator_type>> {}; +template <typename C, template <typename, typename, typename, typename> class T> +struct IsConvertibleToSpecializationImpl< + C, T, y_absl::void_t<typename C::key_type, typename C::hasher, - typename C::key_equal, typename C::allocator_type>> - : std::is_convertible< - C, T<typename C::key_type, typename C::hasher, typename C::key_equal, - typename C::allocator_type>> {}; -template <typename C, - template <typename, typename, typename, typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, + typename C::key_equal, typename C::allocator_type>> + : std::is_convertible< + C, T<typename C::key_type, typename C::hasher, typename C::key_equal, + typename C::allocator_type>> {}; +template <typename C, + template <typename, typename, typename, typename, typename> class T> +struct IsConvertibleToSpecializationImpl< + C, T, y_absl::void_t<typename C::key_type, typename C::mapped_type, - typename C::hasher, typename C::key_equal, - typename C::allocator_type>> - : std::is_convertible<C, T<typename C::key_type, typename C::mapped_type, - typename C::hasher, typename C::key_equal, - typename C::allocator_type>> {}; -template <typename C, template <typename...> class T> -using IsConvertibleToSpecialization = + typename C::hasher, typename C::key_equal, + typename C::allocator_type>> + : std::is_convertible<C, T<typename C::key_type, typename C::mapped_type, + typename C::hasher, typename C::key_equal, + typename C::allocator_type>> {}; +template <typename C, template <typename...> class T> +using IsConvertibleToSpecialization = IsConvertibleToSpecializationImpl<y_absl::decay_t<C>, T>; - -template <typename C> -struct IsConvertibleToArrayImpl : std::false_type {}; -template <template <typename, size_t> class A, typename T, size_t N> -struct IsConvertibleToArrayImpl<A<T, N>> - : std::is_convertible<A<T, N>, std::array<T, N>> {}; -template <typename C> + +template <typename C> +struct IsConvertibleToArrayImpl : std::false_type {}; +template <template <typename, size_t> class A, typename T, size_t N> +struct IsConvertibleToArrayImpl<A<T, N>> + : std::is_convertible<A<T, N>, std::array<T, N>> {}; +template <typename C> using IsConvertibleToArray = IsConvertibleToArrayImpl<y_absl::decay_t<C>>; - -template <typename C> -struct IsConvertibleToBitsetImpl : std::false_type {}; -template <template <size_t> class B, size_t N> -struct IsConvertibleToBitsetImpl<B<N>> - : std::is_convertible<B<N>, std::bitset<N>> {}; -template <typename C> + +template <typename C> +struct IsConvertibleToBitsetImpl : std::false_type {}; +template <template <size_t> class B, size_t N> +struct IsConvertibleToBitsetImpl<B<N>> + : std::is_convertible<B<N>, std::bitset<N>> {}; +template <typename C> using IsConvertibleToBitset = IsConvertibleToBitsetImpl<y_absl::decay_t<C>>; - -template <typename C> -struct IsConvertibleToSTLContainer + +template <typename C> +struct IsConvertibleToSTLContainer : y_absl::disjunction< - IsConvertibleToArray<C>, IsConvertibleToBitset<C>, - IsConvertibleToSpecialization<C, std::deque>, - IsConvertibleToSpecialization<C, std::forward_list>, - IsConvertibleToSpecialization<C, std::list>, - IsConvertibleToSpecialization<C, std::map>, - IsConvertibleToSpecialization<C, std::multimap>, - IsConvertibleToSpecialization<C, std::set>, - IsConvertibleToSpecialization<C, std::multiset>, - IsConvertibleToSpecialization<C, std::unordered_map>, - IsConvertibleToSpecialization<C, std::unordered_multimap>, - IsConvertibleToSpecialization<C, std::unordered_set>, - IsConvertibleToSpecialization<C, std::unordered_multiset>, - IsConvertibleToSpecialization<C, std::vector>> {}; - -template <typename C> -struct IsStrictlyBaseOfAndConvertibleToSTLContainer + IsConvertibleToArray<C>, IsConvertibleToBitset<C>, + IsConvertibleToSpecialization<C, std::deque>, + IsConvertibleToSpecialization<C, std::forward_list>, + IsConvertibleToSpecialization<C, std::list>, + IsConvertibleToSpecialization<C, std::map>, + IsConvertibleToSpecialization<C, std::multimap>, + IsConvertibleToSpecialization<C, std::set>, + IsConvertibleToSpecialization<C, std::multiset>, + IsConvertibleToSpecialization<C, std::unordered_map>, + IsConvertibleToSpecialization<C, std::unordered_multimap>, + IsConvertibleToSpecialization<C, std::unordered_set>, + IsConvertibleToSpecialization<C, std::unordered_multiset>, + IsConvertibleToSpecialization<C, std::vector>> {}; + +template <typename C> +struct IsStrictlyBaseOfAndConvertibleToSTLContainer : y_absl::conjunction<y_absl::negation<IsSTLContainer<C>>, - IsBaseOfSTLContainer<C>, - IsConvertibleToSTLContainer<C>> {}; - -} // namespace strings_internal + IsBaseOfSTLContainer<C>, + IsConvertibleToSTLContainer<C>> {}; + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl -#endif // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ +#endif // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc index 8d5c3b61ac..a421ea6cbb 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc @@ -1,5 +1,5 @@ // Copyright 2020 The Abseil Authors. -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -13,62 +13,62 @@ // limitations under the License. // -// POSIX spec: -// http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html -// +// POSIX spec: +// http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html +// #include "y_absl/strings/internal/str_format/arg.h" - -#include <cassert> -#include <cerrno> -#include <cstdlib> + +#include <cassert> +#include <cerrno> +#include <cstdlib> #include <util/generic/string.h> -#include <type_traits> - +#include <type_traits> + #include "y_absl/base/port.h" #include "y_absl/strings/internal/str_format/float_conversion.h" #include "y_absl/strings/numbers.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { -namespace { - -// Reduce *capacity by s.size(), clipped to a 0 minimum. -void ReducePadding(string_view s, size_t *capacity) { - *capacity = Excess(s.size(), *capacity); -} - -// Reduce *capacity by n, clipped to a 0 minimum. -void ReducePadding(size_t n, size_t *capacity) { - *capacity = Excess(n, *capacity); -} - -template <typename T> -struct MakeUnsigned : std::make_unsigned<T> {}; -template <> +namespace str_format_internal { +namespace { + +// Reduce *capacity by s.size(), clipped to a 0 minimum. +void ReducePadding(string_view s, size_t *capacity) { + *capacity = Excess(s.size(), *capacity); +} + +// Reduce *capacity by n, clipped to a 0 minimum. +void ReducePadding(size_t n, size_t *capacity) { + *capacity = Excess(n, *capacity); +} + +template <typename T> +struct MakeUnsigned : std::make_unsigned<T> {}; +template <> struct MakeUnsigned<y_absl::int128> { using type = y_absl::uint128; -}; -template <> +}; +template <> struct MakeUnsigned<y_absl::uint128> { using type = y_absl::uint128; -}; - -template <typename T> -struct IsSigned : std::is_signed<T> {}; -template <> +}; + +template <typename T> +struct IsSigned : std::is_signed<T> {}; +template <> struct IsSigned<y_absl::int128> : std::true_type {}; -template <> +template <> struct IsSigned<y_absl::uint128> : std::false_type {}; - + // Integral digit printer. // Call one of the PrintAs* routines after construction once. // Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results. class IntDigits { - public: + public: // Print the unsigned integer as octal. // Supports unsigned integral types and uint128. - template <typename T> + template <typename T> void PrintAsOct(T v) { static_assert(!IsSigned<T>::value, ""); char *p = storage_ + sizeof(storage_); @@ -95,10 +95,10 @@ class IntDigits { if (v < 0) { add_neg = true; u = uint128{} - u; - } + } PrintAsDec(u, add_neg); - } - + } + void PrintAsDec(uint128 v, bool add_neg = false) { // This function can be sped up if needed. We can call FastIntToBuffer // twice, or fix FastIntToBuffer to support uint128. @@ -117,11 +117,11 @@ class IntDigits { } size_ = storage_ + sizeof(storage_) - p; start_ = p; - } - + } + // Print the unsigned integer as hex using lowercase. // Supports unsigned integral types and uint128. - template <typename T> + template <typename T> void PrintAsHexLower(T v) { static_assert(!IsSigned<T>::value, ""); char *p = storage_ + sizeof(storage_); @@ -136,14 +136,14 @@ class IntDigits { if (p[0] == '0') { // We printed one too many digits. ++p; - } + } start_ = p; size_ = storage_ + sizeof(storage_) - p; } - + // Print the unsigned integer as hex using uppercase. // Supports unsigned integral types and uint128. - template <typename T> + template <typename T> void PrintAsHexUpper(T v) { static_assert(!IsSigned<T>::value, ""); char *p = storage_ + sizeof(storage_); @@ -155,8 +155,8 @@ class IntDigits { } while (v); start_ = p; size_ = storage_ + sizeof(storage_) - p; - } - + } + // The printed value including the '-' sign if available. // For inputs of value `0`, this will return "0" string_view with_neg_and_zero() const { return {start_, size_}; } @@ -167,19 +167,19 @@ class IntDigits { static_assert('-' < '0', "The check below verifies both."); size_t advance = start_[0] <= '0' ? 1 : 0; return {start_ + advance, size_ - advance}; - } - + } + bool is_negative() const { return start_[0] == '-'; } - + private: const char *start_; size_t size_; // Max size: 128 bit value as octal -> 43 digits, plus sign char char storage_[128 / 3 + 1 + 1]; -}; - -// Note: 'o' conversions do not have a base indicator, it's just that -// the '#' flag is specified to modify the precision for 'o' conversions. +}; + +// Note: 'o' conversions do not have a base indicator, it's just that +// the '#' flag is specified to modify the precision for 'o' conversions. string_view BaseIndicator(const IntDigits &as_digits, const FormatConversionSpecImpl conv) { // always show 0x for %p. @@ -188,94 +188,94 @@ string_view BaseIndicator(const IntDigits &as_digits, bool hex = (conv.conversion_char() == FormatConversionCharInternal::x || conv.conversion_char() == FormatConversionCharInternal::X || conv.conversion_char() == FormatConversionCharInternal::p); - // From the POSIX description of '#' flag: - // "For x or X conversion specifiers, a non-zero result shall have - // 0x (or 0X) prefixed to it." + // From the POSIX description of '#' flag: + // "For x or X conversion specifiers, a non-zero result shall have + // 0x (or 0X) prefixed to it." if (alt && hex && !as_digits.without_neg_or_zero().empty()) { return conv.conversion_char() == FormatConversionCharInternal::X ? "0X" : "0x"; - } - return {}; -} - + } + return {}; +} + string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) { if (conv.conversion_char() == FormatConversionCharInternal::d || conv.conversion_char() == FormatConversionCharInternal::i) { - if (neg) return "-"; + if (neg) return "-"; if (conv.has_show_pos_flag()) return "+"; if (conv.has_sign_col_flag()) return " "; - } - return {}; -} - + } + return {}; +} + bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - size_t fill = 0; - if (conv.width() >= 0) fill = conv.width(); - ReducePadding(1, &fill); + FormatSinkImpl *sink) { + size_t fill = 0; + if (conv.width() >= 0) fill = conv.width(); + ReducePadding(1, &fill); if (!conv.has_left_flag()) sink->Append(fill, ' '); - sink->Append(1, v); + sink->Append(1, v); if (conv.has_left_flag()) sink->Append(fill, ' '); - return true; -} - + return true; +} + bool ConvertIntImplInnerSlow(const IntDigits &as_digits, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { - // Print as a sequence of Substrings: - // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces] - size_t fill = 0; - if (conv.width() >= 0) fill = conv.width(); - + // Print as a sequence of Substrings: + // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces] + size_t fill = 0; + if (conv.width() >= 0) fill = conv.width(); + string_view formatted = as_digits.without_neg_or_zero(); - ReducePadding(formatted, &fill); - + ReducePadding(formatted, &fill); + string_view sign = SignColumn(as_digits.is_negative(), conv); - ReducePadding(sign, &fill); - + ReducePadding(sign, &fill); + string_view base_indicator = BaseIndicator(as_digits, conv); - ReducePadding(base_indicator, &fill); - - int precision = conv.precision(); - bool precision_specified = precision >= 0; - if (!precision_specified) - precision = 1; - + ReducePadding(base_indicator, &fill); + + int precision = conv.precision(); + bool precision_specified = precision >= 0; + if (!precision_specified) + precision = 1; + if (conv.has_alt_flag() && conv.conversion_char() == FormatConversionCharInternal::o) { - // From POSIX description of the '#' (alt) flag: - // "For o conversion, it increases the precision (if necessary) to - // force the first digit of the result to be zero." - if (formatted.empty() || *formatted.begin() != '0') { - int needed = static_cast<int>(formatted.size()) + 1; - precision = std::max(precision, needed); - } - } - - size_t num_zeroes = Excess(formatted.size(), precision); - ReducePadding(num_zeroes, &fill); - + // From POSIX description of the '#' (alt) flag: + // "For o conversion, it increases the precision (if necessary) to + // force the first digit of the result to be zero." + if (formatted.empty() || *formatted.begin() != '0') { + int needed = static_cast<int>(formatted.size()) + 1; + precision = std::max(precision, needed); + } + } + + size_t num_zeroes = Excess(formatted.size(), precision); + ReducePadding(num_zeroes, &fill); + size_t num_left_spaces = !conv.has_left_flag() ? fill : 0; size_t num_right_spaces = conv.has_left_flag() ? fill : 0; - - // From POSIX description of the '0' (zero) flag: - // "For d, i, o, u, x, and X conversion specifiers, if a precision - // is specified, the '0' flag is ignored." + + // From POSIX description of the '0' (zero) flag: + // "For d, i, o, u, x, and X conversion specifiers, if a precision + // is specified, the '0' flag is ignored." if (!precision_specified && conv.has_zero_flag()) { - num_zeroes += num_left_spaces; - num_left_spaces = 0; - } - - sink->Append(num_left_spaces, ' '); - sink->Append(sign); - sink->Append(base_indicator); - sink->Append(num_zeroes, '0'); - sink->Append(formatted); - sink->Append(num_right_spaces, ' '); - return true; -} - -template <typename T> + num_zeroes += num_left_spaces; + num_left_spaces = 0; + } + + sink->Append(num_left_spaces, ' '); + sink->Append(sign); + sink->Append(base_indicator); + sink->Append(num_zeroes, '0'); + sink->Append(formatted); + sink->Append(num_right_spaces, ' '); + return true; +} + +template <typename T> bool ConvertIntArg(T v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { using U = typename MakeUnsigned<T>::type; @@ -321,168 +321,168 @@ bool ConvertIntArg(T v, const FormatConversionSpecImpl conv, default: ABSL_INTERNAL_ASSUME(false); - } - + } + if (conv.is_basic()) { sink->Append(as_digits.with_neg_and_zero()); return true; - } + } return ConvertIntImplInnerSlow(as_digits, conv, sink); -} - -template <typename T> +} + +template <typename T> bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return FormatConversionCharIsFloat(conv.conversion_char()) && ConvertFloatImpl(v, conv, sink); -} - +} + inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { + FormatSinkImpl *sink) { if (conv.is_basic()) { - sink->Append(v); - return true; - } - return sink->PutPaddedString(v, conv.width(), conv.precision(), + sink->Append(v); + return true; + } + return sink->PutPaddedString(v, conv.width(), conv.precision(), conv.has_left_flag()); -} - -} // namespace - -// ==================== Strings ==================== +} + +} // namespace + +// ==================== Strings ==================== StringConvertResult FormatConvertImpl(const TString &v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { - return {ConvertStringArg(v, conv, sink)}; -} - + return {ConvertStringArg(v, conv, sink)}; +} + StringConvertResult FormatConvertImpl(string_view v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { - return {ConvertStringArg(v, conv, sink)}; -} - + return {ConvertStringArg(v, conv, sink)}; +} + ArgConvertResult<FormatConversionCharSetUnion( FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { if (conv.conversion_char() == FormatConversionCharInternal::p) - return {FormatConvertImpl(VoidPtr(v), conv, sink).value}; - size_t len; - if (v == nullptr) { - len = 0; - } else if (conv.precision() < 0) { - len = std::strlen(v); - } else { + return {FormatConvertImpl(VoidPtr(v), conv, sink).value}; + size_t len; + if (v == nullptr) { + len = 0; + } else if (conv.precision() < 0) { + len = std::strlen(v); + } else { // If precision is set, we look for the NUL-terminator on the valid range. - len = std::find(v, v + conv.precision(), '\0') - v; - } - return {ConvertStringArg(string_view(v, len), conv, sink)}; -} - -// ==================== Raw pointers ==================== + len = std::find(v, v + conv.precision(), '\0') - v; + } + return {ConvertStringArg(string_view(v, len), conv, sink)}; +} + +// ==================== Raw pointers ==================== ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { - if (!v.value) { - sink->Append("(nil)"); - return {true}; - } + if (!v.value) { + sink->Append("(nil)"); + return {true}; + } IntDigits as_digits; as_digits.PrintAsHexLower(v.value); return {ConvertIntImplInnerSlow(as_digits, conv, sink)}; -} - -// ==================== Floats ==================== +} + +// ==================== Floats ==================== FloatingConvertResult FormatConvertImpl(float v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertFloatArg(v, conv, sink)}; -} + FormatSinkImpl *sink) { + return {ConvertFloatArg(v, conv, sink)}; +} FloatingConvertResult FormatConvertImpl(double v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertFloatArg(v, conv, sink)}; -} -FloatingConvertResult FormatConvertImpl(long double v, + FormatSinkImpl *sink) { + return {ConvertFloatArg(v, conv, sink)}; +} +FloatingConvertResult FormatConvertImpl(long double v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertFloatArg(v, conv, sink)}; -} - -// ==================== Chars ==================== + FormatSinkImpl *sink) { + return {ConvertFloatArg(v, conv, sink)}; +} + +// ==================== Chars ==================== IntegralConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} -IntegralConvertResult FormatConvertImpl(signed char v, + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} +IntegralConvertResult FormatConvertImpl(signed char v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} -IntegralConvertResult FormatConvertImpl(unsigned char v, + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} +IntegralConvertResult FormatConvertImpl(unsigned char v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} - -// ==================== Ints ==================== -IntegralConvertResult FormatConvertImpl(short v, // NOLINT + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} + +// ==================== Ints ==================== +IntegralConvertResult FormatConvertImpl(short v, // NOLINT const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} -IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} +IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} IntegralConvertResult FormatConvertImpl(int v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} IntegralConvertResult FormatConvertImpl(unsigned v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} -IntegralConvertResult FormatConvertImpl(long v, // NOLINT + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} +IntegralConvertResult FormatConvertImpl(long v, // NOLINT const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} -IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} +IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} -IntegralConvertResult FormatConvertImpl(long long v, // NOLINT + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} +IntegralConvertResult FormatConvertImpl(long long v, // NOLINT const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} -IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} +IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} IntegralConvertResult FormatConvertImpl(y_absl::int128 v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} IntegralConvertResult FormatConvertImpl(y_absl::uint128 v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return {ConvertIntArg(v, conv, sink)}; -} - -ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(); - - - -} // namespace str_format_internal - + FormatSinkImpl *sink) { + return {ConvertIntArg(v, conv, sink)}; +} + +ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(); + + + +} // namespace str_format_internal + ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h index 59b7bcc727..d10e8a2433 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h @@ -12,52 +12,52 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ -#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ - -#include <string.h> -#include <wchar.h> - -#include <cstdio> -#include <iomanip> -#include <limits> -#include <memory> -#include <sstream> +#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ +#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ + +#include <string.h> +#include <wchar.h> + +#include <cstdio> +#include <iomanip> +#include <limits> +#include <memory> +#include <sstream> #include <util/generic/string.h> #include <util/stream/str.h> -#include <type_traits> - +#include <type_traits> + #include "y_absl/base/port.h" #include "y_absl/meta/type_traits.h" #include "y_absl/numeric/int128.h" #include "y_absl/strings/internal/str_format/extension.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - + class Cord; -class FormatCountCapture; -class FormatSink; - +class FormatCountCapture; +class FormatSink; + template <y_absl::FormatConversionCharSet C> struct FormatConvertResult; class FormatConversionSpec; -namespace str_format_internal { - -template <typename T, typename = void> -struct HasUserDefinedConvert : std::false_type {}; - -template <typename T> +namespace str_format_internal { + +template <typename T, typename = void> +struct HasUserDefinedConvert : std::false_type {}; + +template <typename T> struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert( std::declval<const T&>(), std::declval<const FormatConversionSpec&>(), std::declval<FormatSink*>()))>> : std::true_type {}; - + void AbslFormatConvert(); // Stops the lexical name lookup -template <typename T> +template <typename T> auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv, FormatSinkImpl* sink) -> decltype(AbslFormatConvert(v, @@ -73,12 +73,12 @@ auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv, } template <typename T> -class StreamedWrapper; - -// If 'v' can be converted (in the printf sense) according to 'conv', -// then convert it, appending to `sink` and return `true`. -// Otherwise fail and return `false`. - +class StreamedWrapper; + +// If 'v' can be converted (in the printf sense) according to 'conv', +// then convert it, appending to `sink` and return `true`. +// Otherwise fail and return `false`. + // AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v' // as an extension mechanism. These FormatConvertImpl functions are the default // implementations. @@ -86,16 +86,16 @@ class StreamedWrapper; // serves as a disambiguator to reject possible unintended 'AbslFormatConvert' // functions in the namespaces associated with 'v'. -// Raw pointers. -struct VoidPtr { - VoidPtr() = default; - template <typename T, - decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0> - VoidPtr(T* ptr) // NOLINT - : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {} - uintptr_t value; -}; - +// Raw pointers. +struct VoidPtr { + VoidPtr() = default; + template <typename T, + decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0> + VoidPtr(T* ptr) // NOLINT + : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {} + uintptr_t value; +}; + template <FormatConversionCharSet C> struct ArgConvertResult { bool value; @@ -116,7 +116,7 @@ using StringConvertResult = ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -// Strings. +// Strings. StringConvertResult FormatConvertImpl(const TString& v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); @@ -135,28 +135,28 @@ ArgConvertResult<FormatConversionCharSetUnion( FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv, FormatSinkImpl* sink); - + template <class AbslCord, typename std::enable_if<std::is_same< AbslCord, y_absl::Cord>::value>::type* = nullptr> StringConvertResult FormatConvertImpl(const AbslCord& value, FormatConversionSpecImpl conv, FormatSinkImpl* sink) { bool is_left = conv.has_left_flag(); - size_t space_remaining = 0; - - int width = conv.width(); - if (width >= 0) space_remaining = width; - - size_t to_write = value.size(); - - int precision = conv.precision(); - if (precision >= 0) - to_write = (std::min)(to_write, static_cast<size_t>(precision)); - - space_remaining = Excess(to_write, space_remaining); - - if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' '); - + size_t space_remaining = 0; + + int width = conv.width(); + if (width >= 0) space_remaining = width; + + size_t to_write = value.size(); + + int precision = conv.precision(); + if (precision >= 0) + to_write = (std::min)(to_write, static_cast<size_t>(precision)); + + space_remaining = Excess(to_write, space_remaining); + + if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' '); + for (string_view piece : value.Chunks()) { if (piece.size() > to_write) { piece.remove_suffix(piece.size() - to_write); @@ -164,143 +164,143 @@ StringConvertResult FormatConvertImpl(const AbslCord& value, } else { to_write -= piece.size(); } - sink->Append(piece); + sink->Append(piece); if (to_write == 0) { break; } - } - - if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' '); - return {true}; -} - + } + + if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' '); + return {true}; +} + using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion( FormatConversionCharSetInternal::c, FormatConversionCharSetInternal::kNumeric, FormatConversionCharSetInternal::kStar)>; using FloatingConvertResult = ArgConvertResult<FormatConversionCharSetInternal::kFloating>; - -// Floats. + +// Floats. FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); + FormatSinkImpl* sink); FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); + FormatSinkImpl* sink); FloatingConvertResult FormatConvertImpl(long double v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); - -// Chars. + FormatSinkImpl* sink); + +// Chars. IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); + FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(signed char v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); + FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(unsigned char v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); - -// Ints. -IntegralConvertResult FormatConvertImpl(short v, // NOLINT + FormatSinkImpl* sink); + +// Ints. +IntegralConvertResult FormatConvertImpl(short v, // NOLINT FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT + FormatSinkImpl* sink); +IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT FormatConversionSpecImpl conv, - FormatSinkImpl* sink); + FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); + FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(unsigned v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(long v, // NOLINT + FormatSinkImpl* sink); +IntegralConvertResult FormatConvertImpl(long v, // NOLINT FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT + FormatSinkImpl* sink); +IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(long long v, // NOLINT + FormatSinkImpl* sink); +IntegralConvertResult FormatConvertImpl(long long v, // NOLINT FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT + FormatSinkImpl* sink); +IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT FormatConversionSpecImpl conv, - FormatSinkImpl* sink); + FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); + FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(uint128 v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> + FormatSinkImpl* sink); +template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink) { - return FormatConvertImpl(static_cast<int>(v), conv, sink); -} - -// We provide this function to help the checker, but it is never defined. -// FormatArgImpl will use the underlying Convert functions instead. -template <typename T> -typename std::enable_if<std::is_enum<T>::value && - !HasUserDefinedConvert<T>::value, - IntegralConvertResult>::type + FormatSinkImpl* sink) { + return FormatConvertImpl(static_cast<int>(v), conv, sink); +} + +// We provide this function to help the checker, but it is never defined. +// FormatArgImpl will use the underlying Convert functions instead. +template <typename T> +typename std::enable_if<std::is_enum<T>::value && + !HasUserDefinedConvert<T>::value, + IntegralConvertResult>::type FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); - -template <typename T> + +template <typename T> StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, FormatConversionSpecImpl conv, FormatSinkImpl* out) { TString buf; TStringOutput oss(buf); - oss << v.v_; + oss << v.v_; if (!buf) return {false}; return str_format_internal::FormatConvertImpl(buf, conv, out); -} - -// Use templates and dependent types to delay evaluation of the function -// until after FormatCountCapture is fully defined. -struct FormatCountCaptureHelper { - template <class T = int> +} + +// Use templates and dependent types to delay evaluation of the function +// until after FormatCountCapture is fully defined. +struct FormatCountCaptureHelper { + template <class T = int> static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper( const FormatCountCapture& v, FormatConversionSpecImpl conv, FormatSinkImpl* sink) { const y_absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; - + if (conv.conversion_char() != str_format_internal::FormatConversionCharInternal::n) { return {false}; } - *v2.p_ = static_cast<int>(sink->size()); - return {true}; - } -}; - -template <class T = int> + *v2.p_ = static_cast<int>(sink->size()); + return {true}; + } +}; + +template <class T = int> ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl( const FormatCountCapture& v, FormatConversionSpecImpl conv, FormatSinkImpl* sink) { - return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); -} - -// Helper friend struct to hide implementation details from the public API of -// FormatArgImpl. -struct FormatArgImplFriend { - template <typename Arg> - static bool ToInt(Arg arg, int* out) { + return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); +} + +// Helper friend struct to hide implementation details from the public API of +// FormatArgImpl. +struct FormatArgImplFriend { + template <typename Arg> + static bool ToInt(Arg arg, int* out) { // A value initialized FormatConversionSpecImpl has a `none` conv, which // tells the dispatcher to run the `int` conversion. - return arg.dispatcher_(arg.data_, {}, out); - } - - template <typename Arg> + return arg.dispatcher_(arg.data_, {}, out); + } + + template <typename Arg> static bool Convert(Arg arg, FormatConversionSpecImpl conv, - FormatSinkImpl* out) { - return arg.dispatcher_(arg.data_, conv, out); - } - - template <typename Arg> - static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) { - return arg.dispatcher_; - } -}; - + FormatSinkImpl* out) { + return arg.dispatcher_(arg.data_, conv, out); + } + + template <typename Arg> + static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) { + return arg.dispatcher_; + } +}; + template <typename Arg> constexpr FormatConversionCharSet ArgumentToConv() { return y_absl::str_format_internal::ExtractCharSet( @@ -310,219 +310,219 @@ constexpr FormatConversionCharSet ArgumentToConv() { std::declval<FormatSinkImpl*>())){}); } -// A type-erased handle to a format argument. -class FormatArgImpl { - private: - enum { kInlinedSpace = 8 }; - - using VoidPtr = str_format_internal::VoidPtr; - - union Data { - const void* ptr; - const volatile void* volatile_ptr; - char buf[kInlinedSpace]; - }; - +// A type-erased handle to a format argument. +class FormatArgImpl { + private: + enum { kInlinedSpace = 8 }; + + using VoidPtr = str_format_internal::VoidPtr; + + union Data { + const void* ptr; + const volatile void* volatile_ptr; + char buf[kInlinedSpace]; + }; + using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out); - - template <typename T> - struct store_by_value - : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) && - (std::is_integral<T>::value || - std::is_floating_point<T>::value || - std::is_pointer<T>::value || - std::is_same<VoidPtr, T>::value)> {}; - - enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue }; - template <typename T> - struct storage_policy - : std::integral_constant<StoragePolicy, - (std::is_volatile<T>::value - ? ByVolatilePointer - : (store_by_value<T>::value ? ByValue - : ByPointer))> { - }; - - // To reduce the number of vtables we will decay values before hand. - // Anything with a user-defined Convert will get its own vtable. - // For everything else: - // - Decay char* and char arrays into `const char*` - // - Decay any other pointer to `const void*` - // - Decay all enums to their underlying type. - // - Decay function pointers to void*. - template <typename T, typename = void> - struct DecayType { - static constexpr bool kHasUserDefined = - str_format_internal::HasUserDefinedConvert<T>::value; - using type = typename std::conditional< - !kHasUserDefined && std::is_convertible<T, const char*>::value, - const char*, - typename std::conditional<!kHasUserDefined && - std::is_convertible<T, VoidPtr>::value, - VoidPtr, const T&>::type>::type; - }; - template <typename T> - struct DecayType<T, - typename std::enable_if< - !str_format_internal::HasUserDefinedConvert<T>::value && - std::is_enum<T>::value>::type> { - using type = typename std::underlying_type<T>::type; - }; - - public: - template <typename T> - explicit FormatArgImpl(const T& value) { - using D = typename DecayType<T>::type; - static_assert( - std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue, - "Decayed types must be stored by value"); - Init(static_cast<D>(value)); - } - - private: - friend struct str_format_internal::FormatArgImplFriend; - template <typename T, StoragePolicy = storage_policy<T>::value> - struct Manager; - - template <typename T> - struct Manager<T, ByPointer> { - static Data SetValue(const T& value) { - Data data; - data.ptr = std::addressof(value); - return data; - } - - static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); } - }; - - template <typename T> - struct Manager<T, ByVolatilePointer> { - static Data SetValue(const T& value) { - Data data; - data.volatile_ptr = &value; - return data; - } - - static const T& Value(Data arg) { - return *static_cast<const T*>(arg.volatile_ptr); - } - }; - - template <typename T> - struct Manager<T, ByValue> { - static Data SetValue(const T& value) { - Data data; - memcpy(data.buf, &value, sizeof(value)); - return data; - } - - static T Value(Data arg) { - T value; - memcpy(&value, arg.buf, sizeof(T)); - return value; - } - }; - - template <typename T> - void Init(const T& value) { - data_ = Manager<T>::SetValue(value); - dispatcher_ = &Dispatch<T>; - } - - template <typename T> - static int ToIntVal(const T& val) { - using CommonType = typename std::conditional<std::is_signed<T>::value, - int64_t, uint64_t>::type; - if (static_cast<CommonType>(val) > - static_cast<CommonType>((std::numeric_limits<int>::max)())) { - return (std::numeric_limits<int>::max)(); - } else if (std::is_signed<T>::value && - static_cast<CommonType>(val) < - static_cast<CommonType>((std::numeric_limits<int>::min)())) { - return (std::numeric_limits<int>::min)(); - } - return static_cast<int>(val); - } - - template <typename T> - static bool ToInt(Data arg, int* out, std::true_type /* is_integral */, - std::false_type) { - *out = ToIntVal(Manager<T>::Value(arg)); - return true; - } - - template <typename T> - static bool ToInt(Data arg, int* out, std::false_type, - std::true_type /* is_enum */) { - *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>( - Manager<T>::Value(arg))); - return true; - } - - template <typename T> - static bool ToInt(Data, int*, std::false_type, std::false_type) { - return false; - } - - template <typename T> + + template <typename T> + struct store_by_value + : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) && + (std::is_integral<T>::value || + std::is_floating_point<T>::value || + std::is_pointer<T>::value || + std::is_same<VoidPtr, T>::value)> {}; + + enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue }; + template <typename T> + struct storage_policy + : std::integral_constant<StoragePolicy, + (std::is_volatile<T>::value + ? ByVolatilePointer + : (store_by_value<T>::value ? ByValue + : ByPointer))> { + }; + + // To reduce the number of vtables we will decay values before hand. + // Anything with a user-defined Convert will get its own vtable. + // For everything else: + // - Decay char* and char arrays into `const char*` + // - Decay any other pointer to `const void*` + // - Decay all enums to their underlying type. + // - Decay function pointers to void*. + template <typename T, typename = void> + struct DecayType { + static constexpr bool kHasUserDefined = + str_format_internal::HasUserDefinedConvert<T>::value; + using type = typename std::conditional< + !kHasUserDefined && std::is_convertible<T, const char*>::value, + const char*, + typename std::conditional<!kHasUserDefined && + std::is_convertible<T, VoidPtr>::value, + VoidPtr, const T&>::type>::type; + }; + template <typename T> + struct DecayType<T, + typename std::enable_if< + !str_format_internal::HasUserDefinedConvert<T>::value && + std::is_enum<T>::value>::type> { + using type = typename std::underlying_type<T>::type; + }; + + public: + template <typename T> + explicit FormatArgImpl(const T& value) { + using D = typename DecayType<T>::type; + static_assert( + std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue, + "Decayed types must be stored by value"); + Init(static_cast<D>(value)); + } + + private: + friend struct str_format_internal::FormatArgImplFriend; + template <typename T, StoragePolicy = storage_policy<T>::value> + struct Manager; + + template <typename T> + struct Manager<T, ByPointer> { + static Data SetValue(const T& value) { + Data data; + data.ptr = std::addressof(value); + return data; + } + + static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); } + }; + + template <typename T> + struct Manager<T, ByVolatilePointer> { + static Data SetValue(const T& value) { + Data data; + data.volatile_ptr = &value; + return data; + } + + static const T& Value(Data arg) { + return *static_cast<const T*>(arg.volatile_ptr); + } + }; + + template <typename T> + struct Manager<T, ByValue> { + static Data SetValue(const T& value) { + Data data; + memcpy(data.buf, &value, sizeof(value)); + return data; + } + + static T Value(Data arg) { + T value; + memcpy(&value, arg.buf, sizeof(T)); + return value; + } + }; + + template <typename T> + void Init(const T& value) { + data_ = Manager<T>::SetValue(value); + dispatcher_ = &Dispatch<T>; + } + + template <typename T> + static int ToIntVal(const T& val) { + using CommonType = typename std::conditional<std::is_signed<T>::value, + int64_t, uint64_t>::type; + if (static_cast<CommonType>(val) > + static_cast<CommonType>((std::numeric_limits<int>::max)())) { + return (std::numeric_limits<int>::max)(); + } else if (std::is_signed<T>::value && + static_cast<CommonType>(val) < + static_cast<CommonType>((std::numeric_limits<int>::min)())) { + return (std::numeric_limits<int>::min)(); + } + return static_cast<int>(val); + } + + template <typename T> + static bool ToInt(Data arg, int* out, std::true_type /* is_integral */, + std::false_type) { + *out = ToIntVal(Manager<T>::Value(arg)); + return true; + } + + template <typename T> + static bool ToInt(Data arg, int* out, std::false_type, + std::true_type /* is_enum */) { + *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>( + Manager<T>::Value(arg))); + return true; + } + + template <typename T> + static bool ToInt(Data, int*, std::false_type, std::false_type) { + return false; + } + + template <typename T> static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) { - // A `none` conv indicates that we want the `int` conversion. + // A `none` conv indicates that we want the `int` conversion. if (ABSL_PREDICT_FALSE(spec.conversion_char() == FormatConversionCharInternal::kNone)) { - return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(), - std::is_enum<T>()); - } + return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(), + std::is_enum<T>()); + } if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(), spec.conversion_char()))) { return false; } - return str_format_internal::FormatConvertImpl( + return str_format_internal::FormatConvertImpl( Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out)) - .value; - } - - Data data_; - Dispatcher dispatcher_; -}; - + .value; + } + + Data data_; + Dispatcher dispatcher_; +}; + #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \ void*) - -#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \ - __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short, /* NOLINT */ \ - __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */ \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long, /* NOLINT */ \ - __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */ \ - __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \ - __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \ + +#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short, /* NOLINT */ \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */ \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long, /* NOLINT */ \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */ \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(TString, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__) - -ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern); - - -} // namespace str_format_internal + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__) + +ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern); + + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc index 211ce25dea..b1a1a321a9 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc @@ -13,73 +13,73 @@ // limitations under the License. #include "y_absl/strings/internal/str_format/bind.h" - -#include <cerrno> -#include <limits> -#include <sstream> + +#include <cerrno> +#include <limits> +#include <sstream> #include <util/generic/string.h> - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - -namespace { - -inline bool BindFromPosition(int position, int* value, +namespace str_format_internal { + +namespace { + +inline bool BindFromPosition(int position, int* value, y_absl::Span<const FormatArgImpl> pack) { - assert(position > 0); - if (static_cast<size_t>(position) > pack.size()) { - return false; - } - // -1 because positions are 1-based - return FormatArgImplFriend::ToInt(pack[position - 1], value); -} - -class ArgContext { - public: + assert(position > 0); + if (static_cast<size_t>(position) > pack.size()) { + return false; + } + // -1 because positions are 1-based + return FormatArgImplFriend::ToInt(pack[position - 1], value); +} + +class ArgContext { + public: explicit ArgContext(y_absl::Span<const FormatArgImpl> pack) : pack_(pack) {} - - // Fill 'bound' with the results of applying the context's argument pack - // to the specified 'unbound'. We synthesize a BoundConversion by - // lining up a UnboundConversion with a user argument. We also - // resolve any '*' specifiers for width and precision, so after - // this call, 'bound' has all the information it needs to be formatted. - // Returns false on failure. - bool Bind(const UnboundConversion* unbound, BoundConversion* bound); - - private: + + // Fill 'bound' with the results of applying the context's argument pack + // to the specified 'unbound'. We synthesize a BoundConversion by + // lining up a UnboundConversion with a user argument. We also + // resolve any '*' specifiers for width and precision, so after + // this call, 'bound' has all the information it needs to be formatted. + // Returns false on failure. + bool Bind(const UnboundConversion* unbound, BoundConversion* bound); + + private: y_absl::Span<const FormatArgImpl> pack_; -}; - -inline bool ArgContext::Bind(const UnboundConversion* unbound, - BoundConversion* bound) { - const FormatArgImpl* arg = nullptr; - int arg_position = unbound->arg_position; - if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false; - arg = &pack_[arg_position - 1]; // 1-based - +}; + +inline bool ArgContext::Bind(const UnboundConversion* unbound, + BoundConversion* bound) { + const FormatArgImpl* arg = nullptr; + int arg_position = unbound->arg_position; + if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false; + arg = &pack_[arg_position - 1]; // 1-based + if (unbound->flags != Flags::kBasic) { - int width = unbound->width.value(); - bool force_left = false; - if (unbound->width.is_from_arg()) { - if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_)) - return false; - if (width < 0) { - // "A negative field width is taken as a '-' flag followed by a - // positive field width." - force_left = true; - // Make sure we don't overflow the width when negating it. - width = -std::max(width, -std::numeric_limits<int>::max()); - } - } - - int precision = unbound->precision.value(); - if (unbound->precision.is_from_arg()) { - if (!BindFromPosition(unbound->precision.get_from_arg(), &precision, - pack_)) - return false; - } - + int width = unbound->width.value(); + bool force_left = false; + if (unbound->width.is_from_arg()) { + if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_)) + return false; + if (width < 0) { + // "A negative field width is taken as a '-' flag followed by a + // positive field width." + force_left = true; + // Make sure we don't overflow the width when negating it. + width = -std::max(width, -std::numeric_limits<int>::max()); + } + } + + int precision = unbound->precision.value(); + if (unbound->precision.is_from_arg()) { + if (!BindFromPosition(unbound->precision.get_from_arg(), &precision, + pack_)) + return false; + } + FormatConversionSpecImplFriend::SetWidth(width, bound); FormatConversionSpecImplFriend::SetPrecision(precision, bound); @@ -89,170 +89,170 @@ inline bool ArgContext::Bind(const UnboundConversion* unbound, } else { FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound); } - } else { + } else { FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound); FormatConversionSpecImplFriend::SetWidth(-1, bound); FormatConversionSpecImplFriend::SetPrecision(-1, bound); - } + } FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound); - bound->set_arg(arg); - return true; -} - -template <typename Converter> -class ConverterConsumer { - public: + bound->set_arg(arg); + return true; +} + +template <typename Converter> +class ConverterConsumer { + public: ConverterConsumer(Converter converter, y_absl::Span<const FormatArgImpl> pack) - : converter_(converter), arg_context_(pack) {} - - bool Append(string_view s) { - converter_.Append(s); - return true; - } - bool ConvertOne(const UnboundConversion& conv, string_view conv_string) { - BoundConversion bound; - if (!arg_context_.Bind(&conv, &bound)) return false; - return converter_.ConvertOne(bound, conv_string); - } - - private: - Converter converter_; - ArgContext arg_context_; -}; - -template <typename Converter> -bool ConvertAll(const UntypedFormatSpecImpl format, + : converter_(converter), arg_context_(pack) {} + + bool Append(string_view s) { + converter_.Append(s); + return true; + } + bool ConvertOne(const UnboundConversion& conv, string_view conv_string) { + BoundConversion bound; + if (!arg_context_.Bind(&conv, &bound)) return false; + return converter_.ConvertOne(bound, conv_string); + } + + private: + Converter converter_; + ArgContext arg_context_; +}; + +template <typename Converter> +bool ConvertAll(const UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args, Converter converter) { - if (format.has_parsed_conversion()) { - return format.parsed_conversion()->ProcessFormat( - ConverterConsumer<Converter>(converter, args)); - } else { - return ParseFormatString(format.str(), - ConverterConsumer<Converter>(converter, args)); - } -} - -class DefaultConverter { - public: - explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {} - - void Append(string_view s) const { sink_->Append(s); } - - bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const { - return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_); - } - - private: - FormatSinkImpl* sink_; -}; - -class SummarizingConverter { - public: - explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {} - - void Append(string_view s) const { sink_->Append(s); } - - bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const { - UntypedFormatSpecImpl spec("%d"); - - std::ostringstream ss; + if (format.has_parsed_conversion()) { + return format.parsed_conversion()->ProcessFormat( + ConverterConsumer<Converter>(converter, args)); + } else { + return ParseFormatString(format.str(), + ConverterConsumer<Converter>(converter, args)); + } +} + +class DefaultConverter { + public: + explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {} + + void Append(string_view s) const { sink_->Append(s); } + + bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const { + return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_); + } + + private: + FormatSinkImpl* sink_; +}; + +class SummarizingConverter { + public: + explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {} + + void Append(string_view s) const { sink_->Append(s); } + + bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const { + UntypedFormatSpecImpl spec("%d"); + + std::ostringstream ss; ss << "{" << Streamable(spec, {*bound.arg()}) << ":" << FormatConversionSpecImplFriend::FlagsToString(bound); - if (bound.width() >= 0) ss << bound.width(); - if (bound.precision() >= 0) ss << "." << bound.precision(); + if (bound.width() >= 0) ss << bound.width(); + if (bound.precision() >= 0) ss << "." << bound.precision(); ss << bound.conversion_char() << "}"; - Append(ss.str()); - return true; - } - - private: - FormatSinkImpl* sink_; -}; - -} // namespace - -bool BindWithPack(const UnboundConversion* props, + Append(ss.str()); + return true; + } + + private: + FormatSinkImpl* sink_; +}; + +} // namespace + +bool BindWithPack(const UnboundConversion* props, y_absl::Span<const FormatArgImpl> pack, - BoundConversion* bound) { - return ArgContext(pack).Bind(props, bound); -} - + BoundConversion* bound) { + return ArgContext(pack).Bind(props, bound); +} + TString Summarize(const UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args) { - typedef SummarizingConverter Converter; + typedef SummarizingConverter Converter; TString out; - { - // inner block to destroy sink before returning out. It ensures a last - // flush. - FormatSinkImpl sink(&out); - if (!ConvertAll(format, args, Converter(&sink))) { - return ""; - } - } - return out; -} - -bool FormatUntyped(FormatRawSinkImpl raw_sink, - const UntypedFormatSpecImpl format, + { + // inner block to destroy sink before returning out. It ensures a last + // flush. + FormatSinkImpl sink(&out); + if (!ConvertAll(format, args, Converter(&sink))) { + return ""; + } + } + return out; +} + +bool FormatUntyped(FormatRawSinkImpl raw_sink, + const UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args) { - FormatSinkImpl sink(raw_sink); - using Converter = DefaultConverter; - return ConvertAll(format, args, Converter(&sink)); -} - -std::ostream& Streamable::Print(std::ostream& os) const { - if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit); - return os; -} - + FormatSinkImpl sink(raw_sink); + using Converter = DefaultConverter; + return ConvertAll(format, args, Converter(&sink)); +} + +std::ostream& Streamable::Print(std::ostream& os) const { + if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit); + return os; +} + TString& AppendPack(TString* out, const UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args) { - size_t orig = out->size(); - if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) { - out->erase(orig); - } - return *out; -} - + size_t orig = out->size(); + if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) { + out->erase(orig); + } + return *out; +} + TString FormatPack(const UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args) { TString out; - if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) { - out.clear(); - } - return out; -} - -int FprintF(std::FILE* output, const UntypedFormatSpecImpl format, + if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) { + out.clear(); + } + return out; +} + +int FprintF(std::FILE* output, const UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args) { - FILERawSink sink(output); - if (!FormatUntyped(&sink, format, args)) { - errno = EINVAL; - return -1; - } - if (sink.error()) { - errno = sink.error(); - return -1; - } + FILERawSink sink(output); + if (!FormatUntyped(&sink, format, args)) { + errno = EINVAL; + return -1; + } + if (sink.error()) { + errno = sink.error(); + return -1; + } if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) { - errno = EFBIG; - return -1; - } - return static_cast<int>(sink.count()); -} - -int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format, + errno = EFBIG; + return -1; + } + return static_cast<int>(sink.count()); +} + +int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args) { - BufferRawSink sink(output, size ? size - 1 : 0); - if (!FormatUntyped(&sink, format, args)) { - errno = EINVAL; - return -1; - } - size_t total = sink.total_written(); - if (size) output[std::min(total, size - 1)] = 0; - return static_cast<int>(total); -} - -} // namespace str_format_internal + BufferRawSink sink(output, size ? size - 1 : 0); + if (!FormatUntyped(&sink, format, args)) { + errno = EINVAL; + return -1; + } + size_t total = sink.total_written(); + if (size) output[std::min(total, size - 1)] = 0; + return static_cast<int>(total); +} + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h index 3966610710..7f2eb2094f 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h @@ -12,206 +12,206 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ -#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ - -#include <array> -#include <cstdio> -#include <sstream> +#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ +#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ + +#include <array> +#include <cstdio> +#include <sstream> #include <util/generic/string.h> - + #include "y_absl/base/port.h" #include "y_absl/strings/internal/str_format/arg.h" #include "y_absl/strings/internal/str_format/checker.h" #include "y_absl/strings/internal/str_format/parser.h" #include "y_absl/types/span.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -class UntypedFormatSpec; - -namespace str_format_internal { - + +class UntypedFormatSpec; + +namespace str_format_internal { + class BoundConversion : public FormatConversionSpecImpl { - public: - const FormatArgImpl* arg() const { return arg_; } - void set_arg(const FormatArgImpl* a) { arg_ = a; } - - private: - const FormatArgImpl* arg_; -}; - -// This is the type-erased class that the implementation uses. -class UntypedFormatSpecImpl { - public: - UntypedFormatSpecImpl() = delete; - - explicit UntypedFormatSpecImpl(string_view s) - : data_(s.data()), size_(s.size()) {} - explicit UntypedFormatSpecImpl( - const str_format_internal::ParsedFormatBase* pc) - : data_(pc), size_(~size_t{}) {} - - bool has_parsed_conversion() const { return size_ == ~size_t{}; } - - string_view str() const { - assert(!has_parsed_conversion()); - return string_view(static_cast<const char*>(data_), size_); - } - const str_format_internal::ParsedFormatBase* parsed_conversion() const { - assert(has_parsed_conversion()); - return static_cast<const str_format_internal::ParsedFormatBase*>(data_); - } - - template <typename T> - static const UntypedFormatSpecImpl& Extract(const T& s) { - return s.spec_; - } - - private: - const void* data_; - size_t size_; -}; - + public: + const FormatArgImpl* arg() const { return arg_; } + void set_arg(const FormatArgImpl* a) { arg_ = a; } + + private: + const FormatArgImpl* arg_; +}; + +// This is the type-erased class that the implementation uses. +class UntypedFormatSpecImpl { + public: + UntypedFormatSpecImpl() = delete; + + explicit UntypedFormatSpecImpl(string_view s) + : data_(s.data()), size_(s.size()) {} + explicit UntypedFormatSpecImpl( + const str_format_internal::ParsedFormatBase* pc) + : data_(pc), size_(~size_t{}) {} + + bool has_parsed_conversion() const { return size_ == ~size_t{}; } + + string_view str() const { + assert(!has_parsed_conversion()); + return string_view(static_cast<const char*>(data_), size_); + } + const str_format_internal::ParsedFormatBase* parsed_conversion() const { + assert(has_parsed_conversion()); + return static_cast<const str_format_internal::ParsedFormatBase*>(data_); + } + + template <typename T> + static const UntypedFormatSpecImpl& Extract(const T& s) { + return s.spec_; + } + + private: + const void* data_; + size_t size_; +}; + template <typename T, FormatConversionCharSet...> -struct MakeDependent { - using type = T; -}; - -// Implicitly convertible from `const char*`, `string_view`, and the -// `ExtendedParsedFormat` type. This abstraction allows all format functions to -// operate on any without providing too many overloads. +struct MakeDependent { + using type = T; +}; + +// Implicitly convertible from `const char*`, `string_view`, and the +// `ExtendedParsedFormat` type. This abstraction allows all format functions to +// operate on any without providing too many overloads. template <FormatConversionCharSet... Args> -class FormatSpecTemplate - : public MakeDependent<UntypedFormatSpec, Args...>::type { - using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; - - public: +class FormatSpecTemplate + : public MakeDependent<UntypedFormatSpec, Args...>::type { + using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; + + public: #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - + // Honeypot overload for when the string is not constexpr. - // We use the 'unavailable' attribute to give a better compiler error than - // just 'method is deleted'. - FormatSpecTemplate(...) // NOLINT + // We use the 'unavailable' attribute to give a better compiler error than + // just 'method is deleted'. + FormatSpecTemplate(...) // NOLINT __attribute__((unavailable("Format string is not constexpr."))); - - // Honeypot overload for when the format is constexpr and invalid. - // We use the 'unavailable' attribute to give a better compiler error than - // just 'method is deleted'. - // To avoid checking the format twice, we just check that the format is + + // Honeypot overload for when the format is constexpr and invalid. + // We use the 'unavailable' attribute to give a better compiler error than + // just 'method is deleted'. + // To avoid checking the format twice, we just check that the format is // constexpr. If it is valid, then the overload below will kick in. - // We add the template here to make this overload have lower priority. - template <typename = void> - FormatSpecTemplate(const char* s) // NOLINT - __attribute__(( - enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"), - unavailable( - "Format specified does not match the arguments passed."))); - - template <typename T = void> - FormatSpecTemplate(string_view s) // NOLINT - __attribute__((enable_if(str_format_internal::EnsureConstexpr(s), - "constexpr trap"))) { - static_assert(sizeof(T*) == 0, - "Format specified does not match the arguments passed."); - } - - // Good format overload. - FormatSpecTemplate(const char* s) // NOLINT + // We add the template here to make this overload have lower priority. + template <typename = void> + FormatSpecTemplate(const char* s) // NOLINT + __attribute__(( + enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"), + unavailable( + "Format specified does not match the arguments passed."))); + + template <typename T = void> + FormatSpecTemplate(string_view s) // NOLINT + __attribute__((enable_if(str_format_internal::EnsureConstexpr(s), + "constexpr trap"))) { + static_assert(sizeof(T*) == 0, + "Format specified does not match the arguments passed."); + } + + // Good format overload. + FormatSpecTemplate(const char* s) // NOLINT __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) - : Base(s) {} - - FormatSpecTemplate(string_view s) // NOLINT + : Base(s) {} + + FormatSpecTemplate(string_view s) // NOLINT __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) - : Base(s) {} - -#else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - - FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT - FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT - -#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - + : Base(s) {} + +#else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER + + FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT + FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT + +#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER + template < FormatConversionCharSet... C, typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type, typename = typename std::enable_if<AllOf(Contains(Args, C)...)>::type> - FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT - : Base(&pc) {} -}; - -class Streamable { - public: - Streamable(const UntypedFormatSpecImpl& format, + FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT + : Base(&pc) {} +}; + +class Streamable { + public: + Streamable(const UntypedFormatSpecImpl& format, y_absl::Span<const FormatArgImpl> args) - : format_(format) { - if (args.size() <= ABSL_ARRAYSIZE(few_args_)) { - for (size_t i = 0; i < args.size(); ++i) { - few_args_[i] = args[i]; - } + : format_(format) { + if (args.size() <= ABSL_ARRAYSIZE(few_args_)) { + for (size_t i = 0; i < args.size(); ++i) { + few_args_[i] = args[i]; + } args_ = y_absl::MakeSpan(few_args_, args.size()); - } else { - many_args_.assign(args.begin(), args.end()); - args_ = many_args_; - } - } - - std::ostream& Print(std::ostream& os) const; - - friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { - return l.Print(os); - } - - private: - const UntypedFormatSpecImpl& format_; + } else { + many_args_.assign(args.begin(), args.end()); + args_ = many_args_; + } + } + + std::ostream& Print(std::ostream& os) const; + + friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { + return l.Print(os); + } + + private: + const UntypedFormatSpecImpl& format_; y_absl::Span<const FormatArgImpl> args_; - // if args_.size() is 4 or less: - FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0), - FormatArgImpl(0), FormatArgImpl(0)}; - // if args_.size() is more than 4: - std::vector<FormatArgImpl> many_args_; -}; - -// for testing + // if args_.size() is 4 or less: + FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0), + FormatArgImpl(0), FormatArgImpl(0)}; + // if args_.size() is more than 4: + std::vector<FormatArgImpl> many_args_; +}; + +// for testing TString Summarize(UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args); -bool BindWithPack(const UnboundConversion* props, +bool BindWithPack(const UnboundConversion* props, y_absl::Span<const FormatArgImpl> pack, BoundConversion* bound); - -bool FormatUntyped(FormatRawSinkImpl raw_sink, - UntypedFormatSpecImpl format, + +bool FormatUntyped(FormatRawSinkImpl raw_sink, + UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args); - + TString& AppendPack(TString* out, UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args); - + TString FormatPack(const UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args); - -int FprintF(std::FILE* output, UntypedFormatSpecImpl format, + +int FprintF(std::FILE* output, UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args); -int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, +int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, y_absl::Span<const FormatArgImpl> args); - + // Returned by Streamed(v). Converts via '%s' to the TString created -// by std::ostream << v. -template <typename T> -class StreamedWrapper { - public: - explicit StreamedWrapper(const T& v) : v_(v) { } - - private: - template <typename S> +// by std::ostream << v. +template <typename T> +class StreamedWrapper { + public: + explicit StreamedWrapper(const T& v) : v_(v) { } + + private: + template <typename S> friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl( const StreamedWrapper<S>& v, FormatConversionSpecImpl conv, FormatSinkImpl* out); - const T& v_; -}; - -} // namespace str_format_internal + const T& v_; +}; + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h index 7c530d2507..f3690064e3 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h @@ -12,322 +12,322 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ -#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ - +#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ +#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ + #include "y_absl/base/attributes.h" #include "y_absl/strings/internal/str_format/arg.h" #include "y_absl/strings/internal/str_format/extension.h" - -// Compile time check support for entry points. - -#ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER + +// Compile time check support for entry points. + +#ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER #if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) -#define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1 +#define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1 #endif // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) -#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - +#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - -constexpr bool AllOf() { return true; } - -template <typename... T> -constexpr bool AllOf(bool b, T... t) { - return b && AllOf(t...); -} - +namespace str_format_internal { + +constexpr bool AllOf() { return true; } + +template <typename... T> +constexpr bool AllOf(bool b, T... t) { + return b && AllOf(t...); +} + #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - -constexpr bool ContainsChar(const char* chars, char c) { - return *chars == c || (*chars && ContainsChar(chars + 1, c)); -} - -// A constexpr compatible list of Convs. -struct ConvList { + +constexpr bool ContainsChar(const char* chars, char c) { + return *chars == c || (*chars && ContainsChar(chars + 1, c)); +} + +// A constexpr compatible list of Convs. +struct ConvList { const FormatConversionCharSet* array; - int count; - - // We do the bound check here to avoid having to do it on the callers. + int count; + + // We do the bound check here to avoid having to do it on the callers. // Returning an empty FormatConversionCharSet has the same effect as // short circuiting because it will never match any conversion. constexpr FormatConversionCharSet operator[](int i) const { return i < count ? array[i] : FormatConversionCharSet{}; - } - - constexpr ConvList without_front() const { - return count != 0 ? ConvList{array + 1, count - 1} : *this; - } -}; - -template <size_t count> -struct ConvListT { - // Make sure the array has size > 0. + } + + constexpr ConvList without_front() const { + return count != 0 ? ConvList{array + 1, count - 1} : *this; + } +}; + +template <size_t count> +struct ConvListT { + // Make sure the array has size > 0. FormatConversionCharSet list[count ? count : 1]; -}; - -constexpr char GetChar(string_view str, size_t index) { - return index < str.size() ? str[index] : char{}; -} - -constexpr string_view ConsumeFront(string_view str, size_t len = 1) { - return len <= str.size() ? string_view(str.data() + len, str.size() - len) - : string_view(); -} - -constexpr string_view ConsumeAnyOf(string_view format, const char* chars) { - return ContainsChar(chars, GetChar(format, 0)) - ? ConsumeAnyOf(ConsumeFront(format), chars) - : format; -} - -constexpr bool IsDigit(char c) { return c >= '0' && c <= '9'; } - -// Helper class for the ParseDigits function. -// It encapsulates the two return values we need there. -struct Integer { - string_view format; - int value; - - // If the next character is a '$', consume it. - // Otherwise, make `this` an invalid positional argument. - constexpr Integer ConsumePositionalDollar() const { - return GetChar(format, 0) == '$' ? Integer{ConsumeFront(format), value} - : Integer{format, 0}; - } -}; - -constexpr Integer ParseDigits(string_view format, int value = 0) { - return IsDigit(GetChar(format, 0)) - ? ParseDigits(ConsumeFront(format), - 10 * value + GetChar(format, 0) - '0') - : Integer{format, value}; -} - -// Parse digits for a positional argument. -// The parsing also consumes the '$'. -constexpr Integer ParsePositional(string_view format) { - return ParseDigits(format).ConsumePositionalDollar(); -} - -// Parses a single conversion specifier. -// See ConvParser::Run() for post conditions. -class ConvParser { - constexpr ConvParser SetFormat(string_view format) const { - return ConvParser(format, args_, error_, arg_position_, is_positional_); - } - - constexpr ConvParser SetArgs(ConvList args) const { - return ConvParser(format_, args, error_, arg_position_, is_positional_); - } - - constexpr ConvParser SetError(bool error) const { - return ConvParser(format_, args_, error_ || error, arg_position_, - is_positional_); - } - - constexpr ConvParser SetArgPosition(int arg_position) const { - return ConvParser(format_, args_, error_, arg_position, is_positional_); - } - - // Consumes the next arg and verifies that it matches `conv`. - // `error_` is set if there is no next arg or if it doesn't match `conv`. - constexpr ConvParser ConsumeNextArg(char conv) const { - return SetArgs(args_.without_front()).SetError(!Contains(args_[0], conv)); - } - - // Verify that positional argument `i.value` matches `conv`. - // `error_` is set if `i.value` is not a valid argument or if it doesn't - // match. - constexpr ConvParser VerifyPositional(Integer i, char conv) const { - return SetFormat(i.format).SetError(!Contains(args_[i.value - 1], conv)); - } - - // Parse the position of the arg and store it in `arg_position_`. - constexpr ConvParser ParseArgPosition(Integer arg) const { - return SetFormat(arg.format).SetArgPosition(arg.value); - } - - // Consume the flags. - constexpr ConvParser ParseFlags() const { - return SetFormat(ConsumeAnyOf(format_, "-+ #0")); - } - - // Consume the width. - // If it is '*', we verify that it matches `args_`. `error_` is set if it - // doesn't match. - constexpr ConvParser ParseWidth() const { - return IsDigit(GetChar(format_, 0)) - ? SetFormat(ParseDigits(format_).format) - : GetChar(format_, 0) == '*' - ? is_positional_ - ? VerifyPositional( - ParsePositional(ConsumeFront(format_)), '*') - : SetFormat(ConsumeFront(format_)) - .ConsumeNextArg('*') - : *this; - } - - // Consume the precision. - // If it is '*', we verify that it matches `args_`. `error_` is set if it - // doesn't match. - constexpr ConvParser ParsePrecision() const { - return GetChar(format_, 0) != '.' - ? *this - : GetChar(format_, 1) == '*' - ? is_positional_ - ? VerifyPositional( - ParsePositional(ConsumeFront(format_, 2)), '*') - : SetFormat(ConsumeFront(format_, 2)) - .ConsumeNextArg('*') - : SetFormat(ParseDigits(ConsumeFront(format_)).format); - } - - // Consume the length characters. - constexpr ConvParser ParseLength() const { - return SetFormat(ConsumeAnyOf(format_, "lLhjztq")); - } - - // Consume the conversion character and verify that it matches `args_`. - // `error_` is set if it doesn't match. - constexpr ConvParser ParseConversion() const { - return is_positional_ - ? VerifyPositional({ConsumeFront(format_), arg_position_}, - GetChar(format_, 0)) - : ConsumeNextArg(GetChar(format_, 0)) - .SetFormat(ConsumeFront(format_)); - } - - constexpr ConvParser(string_view format, ConvList args, bool error, - int arg_position, bool is_positional) - : format_(format), - args_(args), - error_(error), - arg_position_(arg_position), - is_positional_(is_positional) {} - - public: - constexpr ConvParser(string_view format, ConvList args, bool is_positional) - : format_(format), - args_(args), - error_(false), - arg_position_(0), - is_positional_(is_positional) {} - - // Consume the whole conversion specifier. - // `format()` will be set to the character after the conversion character. - // `error()` will be set if any of the arguments do not match. - constexpr ConvParser Run() const { - return (is_positional_ ? ParseArgPosition(ParsePositional(format_)) : *this) - .ParseFlags() - .ParseWidth() - .ParsePrecision() - .ParseLength() - .ParseConversion(); - } - - constexpr string_view format() const { return format_; } - constexpr ConvList args() const { return args_; } - constexpr bool error() const { return error_; } - constexpr bool is_positional() const { return is_positional_; } - - private: - string_view format_; - // Current list of arguments. If we are not in positional mode we will consume - // from the front. - ConvList args_; - bool error_; - // Holds the argument position of the conversion character, if we are in - // positional mode. Otherwise, it is unspecified. - int arg_position_; - // Whether we are in positional mode. - // It changes the behavior of '*' and where to find the converted argument. - bool is_positional_; -}; - -// Parses a whole format expression. -// See FormatParser::Run(). -class FormatParser { - static constexpr bool FoundPercent(string_view format) { - return format.empty() || - (GetChar(format, 0) == '%' && GetChar(format, 1) != '%'); - } - - // We use an inner function to increase the recursion limit. - // The inner function consumes up to `limit` characters on every run. - // This increases the limit from 512 to ~512*limit. - static constexpr string_view ConsumeNonPercentInner(string_view format, - int limit = 20) { - return FoundPercent(format) || !limit - ? format - : ConsumeNonPercentInner( - ConsumeFront(format, GetChar(format, 0) == '%' && - GetChar(format, 1) == '%' - ? 2 - : 1), - limit - 1); - } - - // Consume characters until the next conversion spec %. - // It skips %%. - static constexpr string_view ConsumeNonPercent(string_view format) { - return FoundPercent(format) - ? format - : ConsumeNonPercent(ConsumeNonPercentInner(format)); - } - - static constexpr bool IsPositional(string_view format) { - return IsDigit(GetChar(format, 0)) ? IsPositional(ConsumeFront(format)) - : GetChar(format, 0) == '$'; - } - - constexpr bool RunImpl(bool is_positional) const { - // In non-positional mode we require all arguments to be consumed. - // In positional mode just reaching the end of the format without errors is - // enough. - return (format_.empty() && (is_positional || args_.count == 0)) || - (!format_.empty() && - ValidateArg( - ConvParser(ConsumeFront(format_), args_, is_positional).Run())); - } - - constexpr bool ValidateArg(ConvParser conv) const { - return !conv.error() && FormatParser(conv.format(), conv.args()) - .RunImpl(conv.is_positional()); - } - - public: - constexpr FormatParser(string_view format, ConvList args) - : format_(ConsumeNonPercent(format)), args_(args) {} - - // Runs the parser for `format` and `args`. - // It verifies that the format is valid and that all conversion specifiers - // match the arguments passed. - // In non-positional mode it also verfies that all arguments are consumed. - constexpr bool Run() const { - return RunImpl(!format_.empty() && IsPositional(ConsumeFront(format_))); - } - - private: - string_view format_; - // Current list of arguments. - // If we are not in positional mode we will consume from the front and will - // have to be empty in the end. - ConvList args_; -}; - +}; + +constexpr char GetChar(string_view str, size_t index) { + return index < str.size() ? str[index] : char{}; +} + +constexpr string_view ConsumeFront(string_view str, size_t len = 1) { + return len <= str.size() ? string_view(str.data() + len, str.size() - len) + : string_view(); +} + +constexpr string_view ConsumeAnyOf(string_view format, const char* chars) { + return ContainsChar(chars, GetChar(format, 0)) + ? ConsumeAnyOf(ConsumeFront(format), chars) + : format; +} + +constexpr bool IsDigit(char c) { return c >= '0' && c <= '9'; } + +// Helper class for the ParseDigits function. +// It encapsulates the two return values we need there. +struct Integer { + string_view format; + int value; + + // If the next character is a '$', consume it. + // Otherwise, make `this` an invalid positional argument. + constexpr Integer ConsumePositionalDollar() const { + return GetChar(format, 0) == '$' ? Integer{ConsumeFront(format), value} + : Integer{format, 0}; + } +}; + +constexpr Integer ParseDigits(string_view format, int value = 0) { + return IsDigit(GetChar(format, 0)) + ? ParseDigits(ConsumeFront(format), + 10 * value + GetChar(format, 0) - '0') + : Integer{format, value}; +} + +// Parse digits for a positional argument. +// The parsing also consumes the '$'. +constexpr Integer ParsePositional(string_view format) { + return ParseDigits(format).ConsumePositionalDollar(); +} + +// Parses a single conversion specifier. +// See ConvParser::Run() for post conditions. +class ConvParser { + constexpr ConvParser SetFormat(string_view format) const { + return ConvParser(format, args_, error_, arg_position_, is_positional_); + } + + constexpr ConvParser SetArgs(ConvList args) const { + return ConvParser(format_, args, error_, arg_position_, is_positional_); + } + + constexpr ConvParser SetError(bool error) const { + return ConvParser(format_, args_, error_ || error, arg_position_, + is_positional_); + } + + constexpr ConvParser SetArgPosition(int arg_position) const { + return ConvParser(format_, args_, error_, arg_position, is_positional_); + } + + // Consumes the next arg and verifies that it matches `conv`. + // `error_` is set if there is no next arg or if it doesn't match `conv`. + constexpr ConvParser ConsumeNextArg(char conv) const { + return SetArgs(args_.without_front()).SetError(!Contains(args_[0], conv)); + } + + // Verify that positional argument `i.value` matches `conv`. + // `error_` is set if `i.value` is not a valid argument or if it doesn't + // match. + constexpr ConvParser VerifyPositional(Integer i, char conv) const { + return SetFormat(i.format).SetError(!Contains(args_[i.value - 1], conv)); + } + + // Parse the position of the arg and store it in `arg_position_`. + constexpr ConvParser ParseArgPosition(Integer arg) const { + return SetFormat(arg.format).SetArgPosition(arg.value); + } + + // Consume the flags. + constexpr ConvParser ParseFlags() const { + return SetFormat(ConsumeAnyOf(format_, "-+ #0")); + } + + // Consume the width. + // If it is '*', we verify that it matches `args_`. `error_` is set if it + // doesn't match. + constexpr ConvParser ParseWidth() const { + return IsDigit(GetChar(format_, 0)) + ? SetFormat(ParseDigits(format_).format) + : GetChar(format_, 0) == '*' + ? is_positional_ + ? VerifyPositional( + ParsePositional(ConsumeFront(format_)), '*') + : SetFormat(ConsumeFront(format_)) + .ConsumeNextArg('*') + : *this; + } + + // Consume the precision. + // If it is '*', we verify that it matches `args_`. `error_` is set if it + // doesn't match. + constexpr ConvParser ParsePrecision() const { + return GetChar(format_, 0) != '.' + ? *this + : GetChar(format_, 1) == '*' + ? is_positional_ + ? VerifyPositional( + ParsePositional(ConsumeFront(format_, 2)), '*') + : SetFormat(ConsumeFront(format_, 2)) + .ConsumeNextArg('*') + : SetFormat(ParseDigits(ConsumeFront(format_)).format); + } + + // Consume the length characters. + constexpr ConvParser ParseLength() const { + return SetFormat(ConsumeAnyOf(format_, "lLhjztq")); + } + + // Consume the conversion character and verify that it matches `args_`. + // `error_` is set if it doesn't match. + constexpr ConvParser ParseConversion() const { + return is_positional_ + ? VerifyPositional({ConsumeFront(format_), arg_position_}, + GetChar(format_, 0)) + : ConsumeNextArg(GetChar(format_, 0)) + .SetFormat(ConsumeFront(format_)); + } + + constexpr ConvParser(string_view format, ConvList args, bool error, + int arg_position, bool is_positional) + : format_(format), + args_(args), + error_(error), + arg_position_(arg_position), + is_positional_(is_positional) {} + + public: + constexpr ConvParser(string_view format, ConvList args, bool is_positional) + : format_(format), + args_(args), + error_(false), + arg_position_(0), + is_positional_(is_positional) {} + + // Consume the whole conversion specifier. + // `format()` will be set to the character after the conversion character. + // `error()` will be set if any of the arguments do not match. + constexpr ConvParser Run() const { + return (is_positional_ ? ParseArgPosition(ParsePositional(format_)) : *this) + .ParseFlags() + .ParseWidth() + .ParsePrecision() + .ParseLength() + .ParseConversion(); + } + + constexpr string_view format() const { return format_; } + constexpr ConvList args() const { return args_; } + constexpr bool error() const { return error_; } + constexpr bool is_positional() const { return is_positional_; } + + private: + string_view format_; + // Current list of arguments. If we are not in positional mode we will consume + // from the front. + ConvList args_; + bool error_; + // Holds the argument position of the conversion character, if we are in + // positional mode. Otherwise, it is unspecified. + int arg_position_; + // Whether we are in positional mode. + // It changes the behavior of '*' and where to find the converted argument. + bool is_positional_; +}; + +// Parses a whole format expression. +// See FormatParser::Run(). +class FormatParser { + static constexpr bool FoundPercent(string_view format) { + return format.empty() || + (GetChar(format, 0) == '%' && GetChar(format, 1) != '%'); + } + + // We use an inner function to increase the recursion limit. + // The inner function consumes up to `limit` characters on every run. + // This increases the limit from 512 to ~512*limit. + static constexpr string_view ConsumeNonPercentInner(string_view format, + int limit = 20) { + return FoundPercent(format) || !limit + ? format + : ConsumeNonPercentInner( + ConsumeFront(format, GetChar(format, 0) == '%' && + GetChar(format, 1) == '%' + ? 2 + : 1), + limit - 1); + } + + // Consume characters until the next conversion spec %. + // It skips %%. + static constexpr string_view ConsumeNonPercent(string_view format) { + return FoundPercent(format) + ? format + : ConsumeNonPercent(ConsumeNonPercentInner(format)); + } + + static constexpr bool IsPositional(string_view format) { + return IsDigit(GetChar(format, 0)) ? IsPositional(ConsumeFront(format)) + : GetChar(format, 0) == '$'; + } + + constexpr bool RunImpl(bool is_positional) const { + // In non-positional mode we require all arguments to be consumed. + // In positional mode just reaching the end of the format without errors is + // enough. + return (format_.empty() && (is_positional || args_.count == 0)) || + (!format_.empty() && + ValidateArg( + ConvParser(ConsumeFront(format_), args_, is_positional).Run())); + } + + constexpr bool ValidateArg(ConvParser conv) const { + return !conv.error() && FormatParser(conv.format(), conv.args()) + .RunImpl(conv.is_positional()); + } + + public: + constexpr FormatParser(string_view format, ConvList args) + : format_(ConsumeNonPercent(format)), args_(args) {} + + // Runs the parser for `format` and `args`. + // It verifies that the format is valid and that all conversion specifiers + // match the arguments passed. + // In non-positional mode it also verfies that all arguments are consumed. + constexpr bool Run() const { + return RunImpl(!format_.empty() && IsPositional(ConsumeFront(format_))); + } + + private: + string_view format_; + // Current list of arguments. + // If we are not in positional mode we will consume from the front and will + // have to be empty in the end. + ConvList args_; +}; + template <FormatConversionCharSet... C> -constexpr bool ValidFormatImpl(string_view format) { - return FormatParser(format, - {ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)}) - .Run(); -} - -#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - -} // namespace str_format_internal +constexpr bool ValidFormatImpl(string_view format) { + return FormatParser(format, + {ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)}) + .Run(); +} + +#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc index f2a4169ae7..fb0757081d 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc @@ -1,28 +1,28 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/str_format/extension.h" - -#include <errno.h> -#include <algorithm> + +#include <errno.h> +#include <algorithm> #include <util/generic/string.h> - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - +namespace str_format_internal { + TString FlagsToString(Flags v) { TString s; s.append(FlagsContains(v, Flags::kLeft) ? "-" : ""); @@ -30,9 +30,9 @@ TString FlagsToString(Flags v) { s.append(FlagsContains(v, Flags::kSignCol) ? " " : ""); s.append(FlagsContains(v, Flags::kAlt) ? "#" : ""); s.append(FlagsContains(v, Flags::kZero) ? "0" : ""); - return s; -} - + return s; +} + #define ABSL_INTERNAL_X_VAL(id) \ constexpr y_absl::FormatConversionChar FormatConversionCharInternal::id; ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) @@ -58,18 +58,18 @@ constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer; bool FormatSinkImpl::PutPaddedString(string_view value, int width, int precision, bool left) { - size_t space_remaining = 0; + size_t space_remaining = 0; if (width >= 0) space_remaining = width; size_t n = value.size(); if (precision >= 0) n = std::min(n, static_cast<size_t>(precision)); string_view shown(value.data(), n); - space_remaining = Excess(shown.size(), space_remaining); + space_remaining = Excess(shown.size(), space_remaining); if (!left) Append(space_remaining, ' '); - Append(shown); + Append(shown); if (left) Append(space_remaining, ' '); - return true; -} - -} // namespace str_format_internal + return true; +} + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h index e5de5cb6a1..e18b8ae796 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h @@ -1,133 +1,133 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ -#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ - -#include <limits.h> - -#include <cstddef> -#include <cstring> -#include <ostream> - +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ +#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ + +#include <limits.h> + +#include <cstddef> +#include <cstring> +#include <ostream> + #include "y_absl/base/config.h" #include "y_absl/base/port.h" #include "y_absl/meta/type_traits.h" #include "y_absl/strings/internal/str_format/output.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN enum class FormatConversionChar : uint8_t; enum class FormatConversionCharSet : uint64_t; -namespace str_format_internal { - -class FormatRawSinkImpl { - public: - // Implicitly convert from any type that provides the hook function as - // described above. - template <typename T, decltype(str_format_internal::InvokeFlush( - std::declval<T*>(), string_view()))* = nullptr> - FormatRawSinkImpl(T* raw) // NOLINT - : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {} - - void Write(string_view s) { write_(sink_, s); } - - template <typename T> - static FormatRawSinkImpl Extract(T s) { - return s.sink_; - } - - private: - template <typename T> - static void Flush(void* r, string_view s) { - str_format_internal::InvokeFlush(static_cast<T*>(r), s); - } - - void* sink_; - void (*write_)(void*, string_view); -}; - -// An abstraction to which conversions write their string data. -class FormatSinkImpl { - public: - explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {} - - ~FormatSinkImpl() { Flush(); } - - void Flush() { - raw_.Write(string_view(buf_, pos_ - buf_)); - pos_ = buf_; - } - - void Append(size_t n, char c) { - if (n == 0) return; - size_ += n; - auto raw_append = [&](size_t count) { - memset(pos_, c, count); - pos_ += count; - }; - while (n > Avail()) { - n -= Avail(); - if (Avail() > 0) { - raw_append(Avail()); - } - Flush(); - } - raw_append(n); - } - - void Append(string_view v) { - size_t n = v.size(); - if (n == 0) return; - size_ += n; - if (n >= Avail()) { - Flush(); - raw_.Write(v); - return; - } - memcpy(pos_, v.data(), n); - pos_ += n; - } - - size_t size() const { return size_; } - - // Put 'v' to 'sink' with specified width, precision, and left flag. +namespace str_format_internal { + +class FormatRawSinkImpl { + public: + // Implicitly convert from any type that provides the hook function as + // described above. + template <typename T, decltype(str_format_internal::InvokeFlush( + std::declval<T*>(), string_view()))* = nullptr> + FormatRawSinkImpl(T* raw) // NOLINT + : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {} + + void Write(string_view s) { write_(sink_, s); } + + template <typename T> + static FormatRawSinkImpl Extract(T s) { + return s.sink_; + } + + private: + template <typename T> + static void Flush(void* r, string_view s) { + str_format_internal::InvokeFlush(static_cast<T*>(r), s); + } + + void* sink_; + void (*write_)(void*, string_view); +}; + +// An abstraction to which conversions write their string data. +class FormatSinkImpl { + public: + explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {} + + ~FormatSinkImpl() { Flush(); } + + void Flush() { + raw_.Write(string_view(buf_, pos_ - buf_)); + pos_ = buf_; + } + + void Append(size_t n, char c) { + if (n == 0) return; + size_ += n; + auto raw_append = [&](size_t count) { + memset(pos_, c, count); + pos_ += count; + }; + while (n > Avail()) { + n -= Avail(); + if (Avail() > 0) { + raw_append(Avail()); + } + Flush(); + } + raw_append(n); + } + + void Append(string_view v) { + size_t n = v.size(); + if (n == 0) return; + size_ += n; + if (n >= Avail()) { + Flush(); + raw_.Write(v); + return; + } + memcpy(pos_, v.data(), n); + pos_ += n; + } + + size_t size() const { return size_; } + + // Put 'v' to 'sink' with specified width, precision, and left flag. bool PutPaddedString(string_view v, int width, int precision, bool left); - - template <typename T> - T Wrap() { - return T(this); - } - - template <typename T> - static FormatSinkImpl* Extract(T* s) { - return s->sink_; - } - - private: - size_t Avail() const { return buf_ + sizeof(buf_) - pos_; } - - FormatRawSinkImpl raw_; - size_t size_ = 0; - char* pos_ = buf_; - char buf_[1024]; -}; - + + template <typename T> + T Wrap() { + return T(this); + } + + template <typename T> + static FormatSinkImpl* Extract(T* s) { + return s->sink_; + } + + private: + size_t Avail() const { return buf_ + sizeof(buf_) - pos_; } + + FormatRawSinkImpl raw_; + size_t size_ = 0; + char* pos_ = buf_; + char buf_[1024]; +}; + enum class Flags : uint8_t { kBasic = 0, kLeft = 1 << 0, @@ -138,8 +138,8 @@ enum class Flags : uint8_t { // This is not a real flag. It just exists to turn off kBasic when no other // flags are set. This is for when width/precision are specified. kNonBasic = 1 << 5, -}; - +}; + constexpr Flags operator|(Flags a, Flags b) { return static_cast<Flags>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b)); } @@ -155,20 +155,20 @@ inline std::ostream& operator<<(std::ostream& os, Flags v) { return os << FlagsToString(v); } -// clang-format off +// clang-format off #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \ - /* text */ \ + /* text */ \ X_VAL(c) X_SEP X_VAL(s) X_SEP \ - /* ints */ \ - X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \ - X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \ - /* floats */ \ - X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \ - X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \ - /* misc */ \ - X_VAL(n) X_SEP X_VAL(p) + /* ints */ \ + X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \ + X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \ + /* floats */ \ + X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \ + X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \ + /* misc */ \ + X_VAL(n) X_SEP X_VAL(p) // clang-format on - + // This type should not be referenced, it exists only to provide labels // internally that match the values declared in FormatConversionChar in // str_format.h. This is meant to allow internal libraries to use the same @@ -186,9 +186,9 @@ struct FormatConversionCharInternal { // clang-format off enum class Enum : uint8_t { c, s, // text - d, i, o, u, x, X, // int - f, F, e, E, g, G, a, A, // float - n, p, // misc + d, i, o, u, x, X, // int + f, F, e, E, g, G, a, A, // float + n, p, // misc kNone }; // clang-format on @@ -202,7 +202,7 @@ struct FormatConversionCharInternal { static_cast<FormatConversionChar>(Enum::kNone); }; // clang-format on - + inline FormatConversionChar FormatConversionCharFromChar(char c) { switch (c) { #define ABSL_INTERNAL_X_VAL(id) \ @@ -210,10 +210,10 @@ inline FormatConversionChar FormatConversionCharFromChar(char c) { return FormatConversionCharInternal::id; ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) #undef ABSL_INTERNAL_X_VAL - } + } return FormatConversionCharInternal::kNone; } - + inline bool FormatConversionCharIsUpper(FormatConversionChar c) { if (c == FormatConversionCharInternal::X || c == FormatConversionCharInternal::F || @@ -223,9 +223,9 @@ inline bool FormatConversionCharIsUpper(FormatConversionChar c) { return true; } else { return false; - } + } } - + inline bool FormatConversionCharIsFloat(FormatConversionChar c) { if (c == FormatConversionCharInternal::a || c == FormatConversionCharInternal::e || @@ -238,9 +238,9 @@ inline bool FormatConversionCharIsFloat(FormatConversionChar c) { return true; } else { return false; - } + } } - + inline char FormatConversionCharToChar(FormatConversionChar c) { if (c == FormatConversionCharInternal::kNone) { return '\0'; @@ -258,16 +258,16 @@ inline char FormatConversionCharToChar(FormatConversionChar c) { #undef ABSL_INTERNAL_X_VAL #undef ABSL_INTERNAL_X_SEP } - + // The associated char. inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) { char c = FormatConversionCharToChar(v); if (!c) c = '?'; return os << c; } - + struct FormatConversionSpecImplFriend; - + class FormatConversionSpecImpl { public: // Width and precison are not specified, no flags are set. @@ -281,34 +281,34 @@ class FormatConversionSpecImpl { } bool has_alt_flag() const { return FlagsContains(flags_, Flags::kAlt); } bool has_zero_flag() const { return FlagsContains(flags_, Flags::kZero); } - + FormatConversionChar conversion_char() const { - // Keep this field first in the struct . It generates better code when - // accessing it when ConversionSpec is passed by value in registers. + // Keep this field first in the struct . It generates better code when + // accessing it when ConversionSpec is passed by value in registers. static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, ""); - return conv_; - } - - // Returns the specified width. If width is unspecfied, it returns a negative - // value. - int width() const { return width_; } - // Returns the specified precision. If precision is unspecfied, it returns a - // negative value. - int precision() const { return precision_; } - + return conv_; + } + + // Returns the specified width. If width is unspecfied, it returns a negative + // value. + int width() const { return width_; } + // Returns the specified precision. If precision is unspecfied, it returns a + // negative value. + int precision() const { return precision_; } + template <typename T> T Wrap() { return T(*this); } - - private: + + private: friend struct str_format_internal::FormatConversionSpecImplFriend; FormatConversionChar conv_ = FormatConversionCharInternal::kNone; - Flags flags_; - int width_; - int precision_; -}; - + Flags flags_; + int width_; + int precision_; +}; + struct FormatConversionSpecImplFriend final { static void SetFlags(Flags f, FormatConversionSpecImpl* conv) { conv->flags_ = f; @@ -351,18 +351,18 @@ constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) { } constexpr uint64_t FormatConversionCharToConvInt(char conv) { - return + return #define ABSL_INTERNAL_CHAR_SET_CASE(c) \ conv == #c[0] \ ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \ : ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) #undef ABSL_INTERNAL_CHAR_SET_CASE - conv == '*' - ? 1 - : 0; -} - + conv == '*' + ? 1 + : 0; +} + constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) { return static_cast<FormatConversionCharSet>( FormatConversionCharToConvInt(conv)); @@ -374,11 +374,11 @@ struct FormatConversionCharSetInternal { FormatConversionCharToConvValue(#c[0]); ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) #undef ABSL_INTERNAL_CHAR_SET_CASE - - // Used for width/precision '*' specification. + + // Used for width/precision '*' specification. static constexpr FormatConversionCharSet kStar = FormatConversionCharToConvValue('*'); - + static constexpr FormatConversionCharSet kIntegral = FormatConversionCharSetUnion(d, i, u, o, x, X); static constexpr FormatConversionCharSet kFloating = @@ -386,25 +386,25 @@ struct FormatConversionCharSetInternal { static constexpr FormatConversionCharSet kNumeric = FormatConversionCharSetUnion(kIntegral, kFloating); static constexpr FormatConversionCharSet kPointer = p; -}; - -// Type safe OR operator. -// We need this for two reasons: -// 1. operator| on enums makes them decay to integers and the result is an -// integer. We need the result to stay as an enum. -// 2. We use "enum class" which would not work even if we accepted the decay. +}; + +// Type safe OR operator. +// We need this for two reasons: +// 1. operator| on enums makes them decay to integers and the result is an +// integer. We need the result to stay as an enum. +// 2. We use "enum class" which would not work even if we accepted the decay. constexpr FormatConversionCharSet operator|(FormatConversionCharSet a, FormatConversionCharSet b) { return FormatConversionCharSetUnion(a, b); -} - +} + // Overloaded conversion functions to support y_absl::ParsedFormat. -// Get a conversion with a single character in it. +// Get a conversion with a single character in it. constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) { return static_cast<FormatConversionCharSet>( FormatConversionCharToConvValue(c)); -} - +} + // Get a conversion with a single character in it. constexpr FormatConversionCharSet ToFormatConversionCharSet( FormatConversionCharSet c) { @@ -414,32 +414,32 @@ constexpr FormatConversionCharSet ToFormatConversionCharSet( template <typename T> void ToFormatConversionCharSet(T) = delete; -// Checks whether `c` exists in `set`. +// Checks whether `c` exists in `set`. constexpr bool Contains(FormatConversionCharSet set, char c) { return (static_cast<uint64_t>(set) & static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0; -} - -// Checks whether all the characters in `c` are contained in `set` +} + +// Checks whether all the characters in `c` are contained in `set` constexpr bool Contains(FormatConversionCharSet set, FormatConversionCharSet c) { - return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) == - static_cast<uint64_t>(c); -} - + return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) == + static_cast<uint64_t>(c); +} + // Checks whether all the characters in `c` are contained in `set` constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) { return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0; } - -// Return capacity - used, clipped to a minimum of 0. -inline size_t Excess(size_t used, size_t capacity) { - return used < capacity ? capacity - used : 0; -} - -} // namespace str_format_internal - + +// Return capacity - used, clipped to a minimum of 0. +inline size_t Excess(size_t used, size_t capacity) { + return used < capacity ? capacity - used : 0; +} + +} // namespace str_format_internal + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc index c49062538d..fb85d1a5aa 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc @@ -13,15 +13,15 @@ // limitations under the License. #include "y_absl/strings/internal/str_format/float_conversion.h" + +#include <string.h> -#include <string.h> - -#include <algorithm> -#include <cassert> -#include <cmath> +#include <algorithm> +#include <cassert> +#include <cmath> #include <limits> #include <util/generic/string.h> - + #include "y_absl/base/attributes.h" #include "y_absl/base/config.h" #include "y_absl/base/optimization.h" @@ -33,13 +33,13 @@ #include "y_absl/strings/numbers.h" #include "y_absl/types/optional.h" #include "y_absl/types/span.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - -namespace { - +namespace str_format_internal { + +namespace { + using ::y_absl::numeric_internal::IsDoubleDouble; // The code below wants to avoid heap allocations. @@ -933,404 +933,404 @@ void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp, } char *CopyStringTo(y_absl::string_view v, char *out) { - std::memcpy(out, v.data(), v.size()); - return out + v.size(); -} - -template <typename Float> + std::memcpy(out, v.data(), v.size()); + return out + v.size(); +} + +template <typename Float> bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink) { - int w = conv.width() >= 0 ? conv.width() : 0; - int p = conv.precision() >= 0 ? conv.precision() : -1; - char fmt[32]; - { - char *fp = fmt; - *fp++ = '%'; + FormatSinkImpl *sink) { + int w = conv.width() >= 0 ? conv.width() : 0; + int p = conv.precision() >= 0 ? conv.precision() : -1; + char fmt[32]; + { + char *fp = fmt; + *fp++ = '%'; fp = CopyStringTo(FormatConversionSpecImplFriend::FlagsToString(conv), fp); - fp = CopyStringTo("*.*", fp); - if (std::is_same<long double, Float>()) { - *fp++ = 'L'; - } + fp = CopyStringTo("*.*", fp); + if (std::is_same<long double, Float>()) { + *fp++ = 'L'; + } *fp++ = FormatConversionCharToChar(conv.conversion_char()); - *fp = 0; - assert(fp < fmt + sizeof(fmt)); - } + *fp = 0; + assert(fp < fmt + sizeof(fmt)); + } TString space(512, '\0'); y_absl::string_view result; - while (true) { - int n = snprintf(&space[0], space.size(), fmt, w, p, v); - if (n < 0) return false; - if (static_cast<size_t>(n) < space.size()) { + while (true) { + int n = snprintf(&space[0], space.size(), fmt, w, p, v); + if (n < 0) return false; + if (static_cast<size_t>(n) < space.size()) { result = y_absl::string_view(space.data(), n); - break; - } - space.resize(n + 1); - } - sink->Append(result); - return true; -} - -// 128-bits in decimal: ceil(128*log(2)/log(10)) -// or std::numeric_limits<__uint128_t>::digits10 -constexpr int kMaxFixedPrecision = 39; - -constexpr int kBufferLength = /*sign*/ 1 + - /*integer*/ kMaxFixedPrecision + - /*point*/ 1 + - /*fraction*/ kMaxFixedPrecision + - /*exponent e+123*/ 5; - -struct Buffer { - void push_front(char c) { - assert(begin > data); - *--begin = c; - } - void push_back(char c) { - assert(end < data + sizeof(data)); - *end++ = c; - } - void pop_back() { - assert(begin < end); - --end; - } - - char &back() { - assert(begin < end); - return end[-1]; - } - - char last_digit() const { return end[-1] == '.' ? end[-2] : end[-1]; } - - int size() const { return static_cast<int>(end - begin); } - - char data[kBufferLength]; - char *begin; - char *end; -}; - -enum class FormatStyle { Fixed, Precision }; - -// If the value is Inf or Nan, print it and return true. -// Otherwise, return false. -template <typename Float> -bool ConvertNonNumericFloats(char sign_char, Float v, + break; + } + space.resize(n + 1); + } + sink->Append(result); + return true; +} + +// 128-bits in decimal: ceil(128*log(2)/log(10)) +// or std::numeric_limits<__uint128_t>::digits10 +constexpr int kMaxFixedPrecision = 39; + +constexpr int kBufferLength = /*sign*/ 1 + + /*integer*/ kMaxFixedPrecision + + /*point*/ 1 + + /*fraction*/ kMaxFixedPrecision + + /*exponent e+123*/ 5; + +struct Buffer { + void push_front(char c) { + assert(begin > data); + *--begin = c; + } + void push_back(char c) { + assert(end < data + sizeof(data)); + *end++ = c; + } + void pop_back() { + assert(begin < end); + --end; + } + + char &back() { + assert(begin < end); + return end[-1]; + } + + char last_digit() const { return end[-1] == '.' ? end[-2] : end[-1]; } + + int size() const { return static_cast<int>(end - begin); } + + char data[kBufferLength]; + char *begin; + char *end; +}; + +enum class FormatStyle { Fixed, Precision }; + +// If the value is Inf or Nan, print it and return true. +// Otherwise, return false. +template <typename Float> +bool ConvertNonNumericFloats(char sign_char, Float v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { - char text[4], *ptr = text; + char text[4], *ptr = text; if (sign_char != '\0') *ptr++ = sign_char; - if (std::isnan(v)) { + if (std::isnan(v)) { ptr = std::copy_n( FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3, ptr); - } else if (std::isinf(v)) { + } else if (std::isinf(v)) { ptr = std::copy_n( FormatConversionCharIsUpper(conv.conversion_char()) ? "INF" : "inf", 3, ptr); - } else { - return false; - } - - return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1, + } else { + return false; + } + + return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1, conv.has_left_flag()); -} - -// Round up the last digit of the value. -// It will carry over and potentially overflow. 'exp' will be adjusted in that -// case. -template <FormatStyle mode> -void RoundUp(Buffer *buffer, int *exp) { - char *p = &buffer->back(); - while (p >= buffer->begin && (*p == '9' || *p == '.')) { - if (*p == '9') *p = '0'; - --p; - } - - if (p < buffer->begin) { - *p = '1'; - buffer->begin = p; - if (mode == FormatStyle::Precision) { - std::swap(p[1], p[2]); // move the . - ++*exp; - buffer->pop_back(); - } - } else { - ++*p; - } -} - -void PrintExponent(int exp, char e, Buffer *out) { - out->push_back(e); - if (exp < 0) { - out->push_back('-'); - exp = -exp; - } else { - out->push_back('+'); - } - // Exponent digits. - if (exp > 99) { - out->push_back(exp / 100 + '0'); - out->push_back(exp / 10 % 10 + '0'); - out->push_back(exp % 10 + '0'); - } else { - out->push_back(exp / 10 + '0'); - out->push_back(exp % 10 + '0'); - } -} - -template <typename Float, typename Int> -constexpr bool CanFitMantissa() { - return -#if defined(__clang__) && !defined(__SSE3__) - // Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289 - // Casting from long double to uint64_t is miscompiled and drops bits. - (!std::is_same<Float, long double>::value || - !std::is_same<Int, uint64_t>::value) && -#endif - std::numeric_limits<Float>::digits <= std::numeric_limits<Int>::digits; -} - -template <typename Float> -struct Decomposed { +} + +// Round up the last digit of the value. +// It will carry over and potentially overflow. 'exp' will be adjusted in that +// case. +template <FormatStyle mode> +void RoundUp(Buffer *buffer, int *exp) { + char *p = &buffer->back(); + while (p >= buffer->begin && (*p == '9' || *p == '.')) { + if (*p == '9') *p = '0'; + --p; + } + + if (p < buffer->begin) { + *p = '1'; + buffer->begin = p; + if (mode == FormatStyle::Precision) { + std::swap(p[1], p[2]); // move the . + ++*exp; + buffer->pop_back(); + } + } else { + ++*p; + } +} + +void PrintExponent(int exp, char e, Buffer *out) { + out->push_back(e); + if (exp < 0) { + out->push_back('-'); + exp = -exp; + } else { + out->push_back('+'); + } + // Exponent digits. + if (exp > 99) { + out->push_back(exp / 100 + '0'); + out->push_back(exp / 10 % 10 + '0'); + out->push_back(exp % 10 + '0'); + } else { + out->push_back(exp / 10 + '0'); + out->push_back(exp % 10 + '0'); + } +} + +template <typename Float, typename Int> +constexpr bool CanFitMantissa() { + return +#if defined(__clang__) && !defined(__SSE3__) + // Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289 + // Casting from long double to uint64_t is miscompiled and drops bits. + (!std::is_same<Float, long double>::value || + !std::is_same<Int, uint64_t>::value) && +#endif + std::numeric_limits<Float>::digits <= std::numeric_limits<Int>::digits; +} + +template <typename Float> +struct Decomposed { using MantissaType = y_absl::conditional_t<std::is_same<long double, Float>::value, uint128, uint64_t>; static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8, ""); MantissaType mantissa; - int exponent; -}; - -// Decompose the double into an integer mantissa and an exponent. -template <typename Float> -Decomposed<Float> Decompose(Float v) { - int exp; - Float m = std::frexp(v, &exp); - m = std::ldexp(m, std::numeric_limits<Float>::digits); - exp -= std::numeric_limits<Float>::digits; + int exponent; +}; + +// Decompose the double into an integer mantissa and an exponent. +template <typename Float> +Decomposed<Float> Decompose(Float v) { + int exp; + Float m = std::frexp(v, &exp); + m = std::ldexp(m, std::numeric_limits<Float>::digits); + exp -= std::numeric_limits<Float>::digits; return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp}; -} - -// Print 'digits' as decimal. -// In Fixed mode, we add a '.' at the end. -// In Precision mode, we add a '.' after the first digit. -template <FormatStyle mode, typename Int> -int PrintIntegralDigits(Int digits, Buffer *out) { - int printed = 0; - if (digits) { - for (; digits; digits /= 10) out->push_front(digits % 10 + '0'); - printed = out->size(); - if (mode == FormatStyle::Precision) { - out->push_front(*out->begin); - out->begin[1] = '.'; - } else { - out->push_back('.'); - } - } else if (mode == FormatStyle::Fixed) { - out->push_front('0'); - out->push_back('.'); - printed = 1; - } - return printed; -} - -// Back out 'extra_digits' digits and round up if necessary. -bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value, - Buffer *out, int *exp_out) { - if (extra_digits <= 0) return false; - - // Back out the extra digits - out->end -= extra_digits; - - bool needs_to_round_up = [&] { - // We look at the digit just past the end. - // There must be 'extra_digits' extra valid digits after end. - if (*out->end > '5') return true; - if (*out->end < '5') return false; - if (has_leftover_value || std::any_of(out->end + 1, out->end + extra_digits, - [](char c) { return c != '0'; })) - return true; - - // Ends in ...50*, round to even. - return out->last_digit() % 2 == 1; - }(); - - if (needs_to_round_up) { - RoundUp<FormatStyle::Precision>(out, exp_out); - } - return true; -} - -// Print the value into the buffer. -// This will not include the exponent, which will be returned in 'exp_out' for -// Precision mode. -template <typename Int, typename Float, FormatStyle mode> -bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, - int *exp_out) { - assert((CanFitMantissa<Float, Int>())); - - const int int_bits = std::numeric_limits<Int>::digits; - - // In precision mode, we start printing one char to the right because it will - // also include the '.' - // In fixed mode we put the dot afterwards on the right. - out->begin = out->end = - out->data + 1 + kMaxFixedPrecision + (mode == FormatStyle::Precision); - - if (exp >= 0) { - if (std::numeric_limits<Float>::digits + exp > int_bits) { - // The value will overflow the Int - return false; - } - int digits_printed = PrintIntegralDigits<mode>(int_mantissa << exp, out); - int digits_to_zero_pad = precision; - if (mode == FormatStyle::Precision) { - *exp_out = digits_printed - 1; - digits_to_zero_pad -= digits_printed - 1; - if (RemoveExtraPrecision(-digits_to_zero_pad, false, out, exp_out)) { - return true; - } - } - for (; digits_to_zero_pad-- > 0;) out->push_back('0'); - return true; - } - - exp = -exp; - // We need at least 4 empty bits for the next decimal digit. - // We will multiply by 10. - if (exp > int_bits - 4) return false; - - const Int mask = (Int{1} << exp) - 1; - - // Print the integral part first. - int digits_printed = PrintIntegralDigits<mode>(int_mantissa >> exp, out); - int_mantissa &= mask; - - int fractional_count = precision; - if (mode == FormatStyle::Precision) { - if (digits_printed == 0) { - // Find the first non-zero digit, when in Precision mode. - *exp_out = 0; - if (int_mantissa) { - while (int_mantissa <= mask) { - int_mantissa *= 10; - --*exp_out; - } - } - out->push_front(static_cast<char>(int_mantissa >> exp) + '0'); - out->push_back('.'); - int_mantissa &= mask; - } else { - // We already have a digit, and a '.' - *exp_out = digits_printed - 1; - fractional_count -= *exp_out; - if (RemoveExtraPrecision(-fractional_count, int_mantissa != 0, out, - exp_out)) { - // If we had enough digits, return right away. - // The code below will try to round again otherwise. - return true; - } - } - } - - auto get_next_digit = [&] { - int_mantissa *= 10; - int digit = static_cast<int>(int_mantissa >> exp); - int_mantissa &= mask; - return digit; - }; - - // Print fractional_count more digits, if available. - for (; fractional_count > 0; --fractional_count) { - out->push_back(get_next_digit() + '0'); - } - - int next_digit = get_next_digit(); - if (next_digit > 5 || - (next_digit == 5 && (int_mantissa || out->last_digit() % 2 == 1))) { - RoundUp<mode>(out, exp_out); - } - - return true; -} - -template <FormatStyle mode, typename Float> -bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out, - int *exp) { - if (precision > kMaxFixedPrecision) return false; - - // Try with uint64_t. - if (CanFitMantissa<Float, std::uint64_t>() && - FloatToBufferImpl<std::uint64_t, Float, mode>( - static_cast<std::uint64_t>(decomposed.mantissa), - static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp)) - return true; - -#if defined(ABSL_HAVE_INTRINSIC_INT128) - // If that is not enough, try with __uint128_t. - return CanFitMantissa<Float, __uint128_t>() && - FloatToBufferImpl<__uint128_t, Float, mode>( - static_cast<__uint128_t>(decomposed.mantissa), - static_cast<__uint128_t>(decomposed.exponent), precision, out, - exp); -#endif - return false; -} - +} + +// Print 'digits' as decimal. +// In Fixed mode, we add a '.' at the end. +// In Precision mode, we add a '.' after the first digit. +template <FormatStyle mode, typename Int> +int PrintIntegralDigits(Int digits, Buffer *out) { + int printed = 0; + if (digits) { + for (; digits; digits /= 10) out->push_front(digits % 10 + '0'); + printed = out->size(); + if (mode == FormatStyle::Precision) { + out->push_front(*out->begin); + out->begin[1] = '.'; + } else { + out->push_back('.'); + } + } else if (mode == FormatStyle::Fixed) { + out->push_front('0'); + out->push_back('.'); + printed = 1; + } + return printed; +} + +// Back out 'extra_digits' digits and round up if necessary. +bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value, + Buffer *out, int *exp_out) { + if (extra_digits <= 0) return false; + + // Back out the extra digits + out->end -= extra_digits; + + bool needs_to_round_up = [&] { + // We look at the digit just past the end. + // There must be 'extra_digits' extra valid digits after end. + if (*out->end > '5') return true; + if (*out->end < '5') return false; + if (has_leftover_value || std::any_of(out->end + 1, out->end + extra_digits, + [](char c) { return c != '0'; })) + return true; + + // Ends in ...50*, round to even. + return out->last_digit() % 2 == 1; + }(); + + if (needs_to_round_up) { + RoundUp<FormatStyle::Precision>(out, exp_out); + } + return true; +} + +// Print the value into the buffer. +// This will not include the exponent, which will be returned in 'exp_out' for +// Precision mode. +template <typename Int, typename Float, FormatStyle mode> +bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, + int *exp_out) { + assert((CanFitMantissa<Float, Int>())); + + const int int_bits = std::numeric_limits<Int>::digits; + + // In precision mode, we start printing one char to the right because it will + // also include the '.' + // In fixed mode we put the dot afterwards on the right. + out->begin = out->end = + out->data + 1 + kMaxFixedPrecision + (mode == FormatStyle::Precision); + + if (exp >= 0) { + if (std::numeric_limits<Float>::digits + exp > int_bits) { + // The value will overflow the Int + return false; + } + int digits_printed = PrintIntegralDigits<mode>(int_mantissa << exp, out); + int digits_to_zero_pad = precision; + if (mode == FormatStyle::Precision) { + *exp_out = digits_printed - 1; + digits_to_zero_pad -= digits_printed - 1; + if (RemoveExtraPrecision(-digits_to_zero_pad, false, out, exp_out)) { + return true; + } + } + for (; digits_to_zero_pad-- > 0;) out->push_back('0'); + return true; + } + + exp = -exp; + // We need at least 4 empty bits for the next decimal digit. + // We will multiply by 10. + if (exp > int_bits - 4) return false; + + const Int mask = (Int{1} << exp) - 1; + + // Print the integral part first. + int digits_printed = PrintIntegralDigits<mode>(int_mantissa >> exp, out); + int_mantissa &= mask; + + int fractional_count = precision; + if (mode == FormatStyle::Precision) { + if (digits_printed == 0) { + // Find the first non-zero digit, when in Precision mode. + *exp_out = 0; + if (int_mantissa) { + while (int_mantissa <= mask) { + int_mantissa *= 10; + --*exp_out; + } + } + out->push_front(static_cast<char>(int_mantissa >> exp) + '0'); + out->push_back('.'); + int_mantissa &= mask; + } else { + // We already have a digit, and a '.' + *exp_out = digits_printed - 1; + fractional_count -= *exp_out; + if (RemoveExtraPrecision(-fractional_count, int_mantissa != 0, out, + exp_out)) { + // If we had enough digits, return right away. + // The code below will try to round again otherwise. + return true; + } + } + } + + auto get_next_digit = [&] { + int_mantissa *= 10; + int digit = static_cast<int>(int_mantissa >> exp); + int_mantissa &= mask; + return digit; + }; + + // Print fractional_count more digits, if available. + for (; fractional_count > 0; --fractional_count) { + out->push_back(get_next_digit() + '0'); + } + + int next_digit = get_next_digit(); + if (next_digit > 5 || + (next_digit == 5 && (int_mantissa || out->last_digit() % 2 == 1))) { + RoundUp<mode>(out, exp_out); + } + + return true; +} + +template <FormatStyle mode, typename Float> +bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out, + int *exp) { + if (precision > kMaxFixedPrecision) return false; + + // Try with uint64_t. + if (CanFitMantissa<Float, std::uint64_t>() && + FloatToBufferImpl<std::uint64_t, Float, mode>( + static_cast<std::uint64_t>(decomposed.mantissa), + static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp)) + return true; + +#if defined(ABSL_HAVE_INTRINSIC_INT128) + // If that is not enough, try with __uint128_t. + return CanFitMantissa<Float, __uint128_t>() && + FloatToBufferImpl<__uint128_t, Float, mode>( + static_cast<__uint128_t>(decomposed.mantissa), + static_cast<__uint128_t>(decomposed.exponent), precision, out, + exp); +#endif + return false; +} + void WriteBufferToSink(char sign_char, y_absl::string_view str, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { - int left_spaces = 0, zeros = 0, right_spaces = 0; - int missing_chars = - conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) - - static_cast<int>(sign_char != 0), - 0) - : 0; + int left_spaces = 0, zeros = 0, right_spaces = 0; + int missing_chars = + conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) - + static_cast<int>(sign_char != 0), + 0) + : 0; if (conv.has_left_flag()) { - right_spaces = missing_chars; + right_spaces = missing_chars; } else if (conv.has_zero_flag()) { - zeros = missing_chars; - } else { - left_spaces = missing_chars; - } - - sink->Append(left_spaces, ' '); + zeros = missing_chars; + } else { + left_spaces = missing_chars; + } + + sink->Append(left_spaces, ' '); if (sign_char != '\0') sink->Append(1, sign_char); - sink->Append(zeros, '0'); - sink->Append(str); - sink->Append(right_spaces, ' '); -} - -template <typename Float> + sink->Append(zeros, '0'); + sink->Append(str); + sink->Append(right_spaces, ' '); +} + +template <typename Float> bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink) { - // Print the sign or the sign column. - Float abs_v = v; - char sign_char = 0; - if (std::signbit(abs_v)) { - sign_char = '-'; - abs_v = -abs_v; + FormatSinkImpl *sink) { + // Print the sign or the sign column. + Float abs_v = v; + char sign_char = 0; + if (std::signbit(abs_v)) { + sign_char = '-'; + abs_v = -abs_v; } else if (conv.has_show_pos_flag()) { - sign_char = '+'; + sign_char = '+'; } else if (conv.has_sign_col_flag()) { - sign_char = ' '; - } - - // Print nan/inf. - if (ConvertNonNumericFloats(sign_char, abs_v, conv, sink)) { - return true; - } - - int precision = conv.precision() < 0 ? 6 : conv.precision(); - - int exp = 0; - - auto decomposed = Decompose(abs_v); - - Buffer buffer; - + sign_char = ' '; + } + + // Print nan/inf. + if (ConvertNonNumericFloats(sign_char, abs_v, conv, sink)) { + return true; + } + + int precision = conv.precision() < 0 ? 6 : conv.precision(); + + int exp = 0; + + auto decomposed = Decompose(abs_v); + + Buffer buffer; + FormatConversionChar c = conv.conversion_char(); - + if (c == FormatConversionCharInternal::f || c == FormatConversionCharInternal::F) { FormatF(decomposed.mantissa, decomposed.exponent, @@ -1366,7 +1366,7 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, // Have 1.23456, needs 1234.56 // Move the '.' exp positions to the right. std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2); - } + } exp = 0; } if (!conv.has_alt_flag()) { @@ -1386,38 +1386,38 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, return true; } else { return false; - } - - WriteBufferToSink(sign_char, + } + + WriteBufferToSink(sign_char, y_absl::string_view(buffer.begin, buffer.end - buffer.begin), conv, sink); - - return true; -} - -} // namespace - + + return true; +} + +} // namespace + bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink) { + FormatSinkImpl *sink) { if (IsDoubleDouble()) { // This is the `double-double` representation of `long double`. We do not // handle it natively. Fallback to snprintf. return FallbackToSnprintf(v, conv, sink); } - return FloatToSink(v, conv, sink); -} - + return FloatToSink(v, conv, sink); +} + bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink) { + FormatSinkImpl *sink) { return FloatToSink(static_cast<double>(v), conv, sink); -} - +} + bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink) { - return FloatToSink(v, conv, sink); -} - -} // namespace str_format_internal + FormatSinkImpl *sink) { + return FloatToSink(v, conv, sink); +} + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h index d93a415756..049c2c979c 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h @@ -12,26 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ -#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ - +#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ +#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ + #include "y_absl/strings/internal/str_format/extension.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - +namespace str_format_internal { + bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink); - + FormatSinkImpl *sink); + bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink); - + FormatSinkImpl *sink); + bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink); - -} // namespace str_format_internal + FormatSinkImpl *sink); + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.cc index ade3f67ef2..cdf65429db 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.cc @@ -1,72 +1,72 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/str_format/output.h" - -#include <errno.h> -#include <cstring> - + +#include <errno.h> +#include <cstring> + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - -namespace { -struct ClearErrnoGuard { - ClearErrnoGuard() : old_value(errno) { errno = 0; } - ~ClearErrnoGuard() { - if (!errno) errno = old_value; - } - int old_value; -}; -} // namespace - -void BufferRawSink::Write(string_view v) { - size_t to_write = std::min(v.size(), size_); - std::memcpy(buffer_, v.data(), to_write); - buffer_ += to_write; - size_ -= to_write; - total_written_ += v.size(); -} - -void FILERawSink::Write(string_view v) { - while (!v.empty() && !error_) { - // Reset errno to zero in case the libc implementation doesn't set errno - // when a failure occurs. - ClearErrnoGuard guard; - - if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) { - // Some progress was made. - count_ += result; - v.remove_prefix(result); - } else { - if (errno == EINTR) { - continue; - } else if (errno) { - error_ = errno; - } else if (std::ferror(output_)) { - // Non-POSIX compliant libc implementations may not set errno, so we - // have check the streams error indicator. - error_ = EBADF; - } else { - // We're likely on a non-POSIX system that encountered EINTR but had no - // way of reporting it. - continue; - } - } - } -} - -} // namespace str_format_internal +namespace str_format_internal { + +namespace { +struct ClearErrnoGuard { + ClearErrnoGuard() : old_value(errno) { errno = 0; } + ~ClearErrnoGuard() { + if (!errno) errno = old_value; + } + int old_value; +}; +} // namespace + +void BufferRawSink::Write(string_view v) { + size_t to_write = std::min(v.size(), size_); + std::memcpy(buffer_, v.data(), to_write); + buffer_ += to_write; + size_ -= to_write; + total_written_ += v.size(); +} + +void FILERawSink::Write(string_view v) { + while (!v.empty() && !error_) { + // Reset errno to zero in case the libc implementation doesn't set errno + // when a failure occurs. + ClearErrnoGuard guard; + + if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) { + // Some progress was made. + count_ += result; + v.remove_prefix(result); + } else { + if (errno == EINTR) { + continue; + } else if (errno) { + error_ = errno; + } else if (std::ferror(output_)) { + // Non-POSIX compliant libc implementations may not set errno, so we + // have check the streams error indicator. + error_ = EBADF; + } else { + // We're likely on a non-POSIX system that encountered EINTR but had no + // way of reporting it. + continue; + } + } + } +} + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h index 8fc46fbafa..fee403f83e 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h @@ -1,96 +1,96 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Output extension hooks for the Format library. -// `internal::InvokeFlush` calls the appropriate flush function for the -// specified output argument. -// `BufferRawSink` is a simple output sink for a char buffer. Used by SnprintF. -// `FILERawSink` is a std::FILE* based sink. Used by PrintF and FprintF. - -#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ -#define ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ - -#include <cstdio> -#include <ostream> +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Output extension hooks for the Format library. +// `internal::InvokeFlush` calls the appropriate flush function for the +// specified output argument. +// `BufferRawSink` is a simple output sink for a char buffer. Used by SnprintF. +// `FILERawSink` is a std::FILE* based sink. Used by PrintF and FprintF. + +#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ +#define ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ + +#include <cstdio> +#include <ostream> #include <util/generic/string.h> - + #include "y_absl/base/port.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - -// RawSink implementation that writes into a char* buffer. -// It will not overflow the buffer, but will keep the total count of chars -// that would have been written. -class BufferRawSink { - public: - BufferRawSink(char* buffer, size_t size) : buffer_(buffer), size_(size) {} - - size_t total_written() const { return total_written_; } - void Write(string_view v); - - private: - char* buffer_; - size_t size_; - size_t total_written_ = 0; -}; - -// RawSink implementation that writes into a FILE*. -// It keeps track of the total number of bytes written and any error encountered -// during the writes. -class FILERawSink { - public: - explicit FILERawSink(std::FILE* output) : output_(output) {} - - void Write(string_view v); - - size_t count() const { return count_; } - int error() const { return error_; } - - private: - std::FILE* output_; - int error_ = 0; - size_t count_ = 0; -}; - -// Provide RawSink integration with common types from the STL. +namespace str_format_internal { + +// RawSink implementation that writes into a char* buffer. +// It will not overflow the buffer, but will keep the total count of chars +// that would have been written. +class BufferRawSink { + public: + BufferRawSink(char* buffer, size_t size) : buffer_(buffer), size_(size) {} + + size_t total_written() const { return total_written_; } + void Write(string_view v); + + private: + char* buffer_; + size_t size_; + size_t total_written_ = 0; +}; + +// RawSink implementation that writes into a FILE*. +// It keeps track of the total number of bytes written and any error encountered +// during the writes. +class FILERawSink { + public: + explicit FILERawSink(std::FILE* output) : output_(output) {} + + void Write(string_view v); + + size_t count() const { return count_; } + int error() const { return error_; } + + private: + std::FILE* output_; + int error_ = 0; + size_t count_ = 0; +}; + +// Provide RawSink integration with common types from the STL. inline void AbslFormatFlush(TString* out, string_view s) { - out->append(s.data(), s.size()); -} -inline void AbslFormatFlush(std::ostream* out, string_view s) { - out->write(s.data(), s.size()); -} - -inline void AbslFormatFlush(FILERawSink* sink, string_view v) { - sink->Write(v); -} - -inline void AbslFormatFlush(BufferRawSink* sink, string_view v) { - sink->Write(v); -} - + out->append(s.data(), s.size()); +} +inline void AbslFormatFlush(std::ostream* out, string_view s) { + out->write(s.data(), s.size()); +} + +inline void AbslFormatFlush(FILERawSink* sink, string_view v) { + sink->Write(v); +} + +inline void AbslFormatFlush(BufferRawSink* sink, string_view v) { + sink->Write(v); +} + // This is a SFINAE to get a better compiler error message when the type // is not supported. -template <typename T> +template <typename T> auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) { AbslFormatFlush(out, s); -} - -} // namespace str_format_internal +} + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc index af07e32fe5..e6b03cc873 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc @@ -13,24 +13,24 @@ // limitations under the License. #include "y_absl/strings/internal/str_format/parser.h" - -#include <assert.h> -#include <string.h> -#include <wchar.h> -#include <cctype> -#include <cstdint> - -#include <algorithm> -#include <initializer_list> -#include <limits> -#include <ostream> + +#include <assert.h> +#include <string.h> +#include <wchar.h> +#include <cctype> +#include <cstdint> + +#include <algorithm> +#include <initializer_list> +#include <limits> +#include <ostream> #include <util/generic/string.h> -#include <unordered_set> - +#include <unordered_set> + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - +namespace str_format_internal { + using CC = FormatConversionCharInternal; using LM = LengthMod; @@ -41,7 +41,7 @@ constexpr auto f_pos = Flags::kShowPos; constexpr auto f_left = Flags::kLeft; constexpr auto f_zero = Flags::kZero; -ABSL_CONST_INIT const ConvTag kTags[256] = { +ABSL_CONST_INIT const ConvTag kTags[256] = { {}, {}, {}, {}, {}, {}, {}, {}, // 00-07 {}, {}, {}, {}, {}, {}, {}, {}, // 08-0f {}, {}, {}, {}, {}, {}, {}, {}, // 10-17 @@ -74,17 +74,17 @@ ABSL_CONST_INIT const ConvTag kTags[256] = { {}, {}, {}, {}, {}, {}, {}, {}, // e8-ef {}, {}, {}, {}, {}, {}, {}, {}, // f0-f7 {}, {}, {}, {}, {}, {}, {}, {}, // f8-ff -}; - -namespace { - -bool CheckFastPathSetting(const UnboundConversion& conv) { +}; + +namespace { + +bool CheckFastPathSetting(const UnboundConversion& conv) { bool width_precision_needed = conv.width.value() >= 0 || conv.precision.value() >= 0; if (width_precision_needed && conv.flags == Flags::kBasic) { - fprintf(stderr, - "basic=%d left=%d show_pos=%d sign_col=%d alt=%d zero=%d " - "width=%d precision=%d\n", + fprintf(stderr, + "basic=%d left=%d show_pos=%d sign_col=%d alt=%d zero=%d " + "width=%d precision=%d\n", conv.flags == Flags::kBasic ? 1 : 0, FlagsContains(conv.flags, Flags::kLeft) ? 1 : 0, FlagsContains(conv.flags, Flags::kShowPos) ? 1 : 0, @@ -93,57 +93,57 @@ bool CheckFastPathSetting(const UnboundConversion& conv) { FlagsContains(conv.flags, Flags::kZero) ? 1 : 0, conv.width.value(), conv.precision.value()); return false; - } + } return true; -} - -template <bool is_positional> -const char *ConsumeConversion(const char *pos, const char *const end, - UnboundConversion *conv, int *next_arg) { - const char* const original_pos = pos; - char c; - // Read the next char into `c` and update `pos`. Returns false if there are - // no more chars to read. -#define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR() \ - do { \ - if (ABSL_PREDICT_FALSE(pos == end)) return nullptr; \ - c = *pos++; \ - } while (0) - - const auto parse_digits = [&] { - int digits = c - '0'; - // We do not want to overflow `digits` so we consume at most digits10 - // digits. If there are more digits the parsing will fail later on when the - // digit doesn't match the expected characters. - int num_digits = std::numeric_limits<int>::digits10; - for (;;) { - if (ABSL_PREDICT_FALSE(pos == end)) break; - c = *pos++; - if (!std::isdigit(c)) break; - --num_digits; - if (ABSL_PREDICT_FALSE(!num_digits)) break; - digits = 10 * digits + c - '0'; - } - return digits; - }; - - if (is_positional) { - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; - conv->arg_position = parse_digits(); - assert(conv->arg_position > 0); - if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; - } - - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - - // We should start with the basic flag on. +} + +template <bool is_positional> +const char *ConsumeConversion(const char *pos, const char *const end, + UnboundConversion *conv, int *next_arg) { + const char* const original_pos = pos; + char c; + // Read the next char into `c` and update `pos`. Returns false if there are + // no more chars to read. +#define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR() \ + do { \ + if (ABSL_PREDICT_FALSE(pos == end)) return nullptr; \ + c = *pos++; \ + } while (0) + + const auto parse_digits = [&] { + int digits = c - '0'; + // We do not want to overflow `digits` so we consume at most digits10 + // digits. If there are more digits the parsing will fail later on when the + // digit doesn't match the expected characters. + int num_digits = std::numeric_limits<int>::digits10; + for (;;) { + if (ABSL_PREDICT_FALSE(pos == end)) break; + c = *pos++; + if (!std::isdigit(c)) break; + --num_digits; + if (ABSL_PREDICT_FALSE(!num_digits)) break; + digits = 10 * digits + c - '0'; + } + return digits; + }; + + if (is_positional) { + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; + conv->arg_position = parse_digits(); + assert(conv->arg_position > 0); + if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; + } + + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + + // We should start with the basic flag on. assert(conv->flags == Flags::kBasic); - - // Any non alpha character makes this conversion not basic. - // This includes flags (-+ #0), width (1-9, *) or precision (.). - // All conversion characters and length modifiers are alpha characters. - if (c < 'A') { + + // Any non alpha character makes this conversion not basic. + // This includes flags (-+ #0), width (1-9, *) or precision (.). + // All conversion characters and length modifiers are alpha characters. + if (c < 'A') { while (c <= '0') { auto tag = GetTagForChar(c); if (tag.is_flags()) { @@ -151,87 +151,87 @@ const char *ConsumeConversion(const char *pos, const char *const end, ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); } else { break; - } - } - - if (c <= '9') { - if (c >= '0') { - int maybe_width = parse_digits(); - if (!is_positional && c == '$') { - if (ABSL_PREDICT_FALSE(*next_arg != 0)) return nullptr; - // Positional conversion. - *next_arg = -1; - return ConsumeConversion<true>(original_pos, end, conv, next_arg); - } + } + } + + if (c <= '9') { + if (c >= '0') { + int maybe_width = parse_digits(); + if (!is_positional && c == '$') { + if (ABSL_PREDICT_FALSE(*next_arg != 0)) return nullptr; + // Positional conversion. + *next_arg = -1; + return ConsumeConversion<true>(original_pos, end, conv, next_arg); + } conv->flags = conv->flags | Flags::kNonBasic; - conv->width.set_value(maybe_width); - } else if (c == '*') { + conv->width.set_value(maybe_width); + } else if (c == '*') { conv->flags = conv->flags | Flags::kNonBasic; - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - if (is_positional) { - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; - conv->width.set_from_arg(parse_digits()); - if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - } else { - conv->width.set_from_arg(++*next_arg); - } - } - } - - if (c == '.') { + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + if (is_positional) { + if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; + conv->width.set_from_arg(parse_digits()); + if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + } else { + conv->width.set_from_arg(++*next_arg); + } + } + } + + if (c == '.') { conv->flags = conv->flags | Flags::kNonBasic; - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - if (std::isdigit(c)) { - conv->precision.set_value(parse_digits()); - } else if (c == '*') { - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - if (is_positional) { - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; - conv->precision.set_from_arg(parse_digits()); - if (c != '$') return nullptr; - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - } else { - conv->precision.set_from_arg(++*next_arg); - } - } else { - conv->precision.set_value(0); - } - } - } - - auto tag = GetTagForChar(c); - - if (ABSL_PREDICT_FALSE(!tag.is_conv())) { - if (ABSL_PREDICT_FALSE(!tag.is_length())) return nullptr; - - // It is a length modifier. - using str_format_internal::LengthMod; - LengthMod length_mod = tag.as_length(); - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + if (std::isdigit(c)) { + conv->precision.set_value(parse_digits()); + } else if (c == '*') { + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + if (is_positional) { + if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; + conv->precision.set_from_arg(parse_digits()); + if (c != '$') return nullptr; + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + } else { + conv->precision.set_from_arg(++*next_arg); + } + } else { + conv->precision.set_value(0); + } + } + } + + auto tag = GetTagForChar(c); + + if (ABSL_PREDICT_FALSE(!tag.is_conv())) { + if (ABSL_PREDICT_FALSE(!tag.is_length())) return nullptr; + + // It is a length modifier. + using str_format_internal::LengthMod; + LengthMod length_mod = tag.as_length(); + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); if (c == 'h' && length_mod == LengthMod::h) { conv->length_mod = LengthMod::hh; - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); } else if (c == 'l' && length_mod == LengthMod::l) { conv->length_mod = LengthMod::ll; - ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - } else { - conv->length_mod = length_mod; - } - tag = GetTagForChar(c); - if (ABSL_PREDICT_FALSE(!tag.is_conv())) return nullptr; - } - - assert(CheckFastPathSetting(*conv)); - (void)(&CheckFastPathSetting); - - conv->conv = tag.as_conv(); - if (!is_positional) conv->arg_position = ++*next_arg; - return pos; -} - -} // namespace - + ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); + } else { + conv->length_mod = length_mod; + } + tag = GetTagForChar(c); + if (ABSL_PREDICT_FALSE(!tag.is_conv())) return nullptr; + } + + assert(CheckFastPathSetting(*conv)); + (void)(&CheckFastPathSetting); + + conv->conv = tag.as_conv(); + if (!is_positional) conv->arg_position = ++*next_arg; + return pos; +} + +} // namespace + TString LengthModToString(LengthMod v) { switch (v) { case LengthMod::h: @@ -258,82 +258,82 @@ TString LengthModToString(LengthMod v) { return ""; } -const char *ConsumeUnboundConversion(const char *p, const char *end, - UnboundConversion *conv, int *next_arg) { - if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg); - return ConsumeConversion<false>(p, end, conv, next_arg); -} - -struct ParsedFormatBase::ParsedFormatConsumer { - explicit ParsedFormatConsumer(ParsedFormatBase *parsedformat) - : parsed(parsedformat), data_pos(parsedformat->data_.get()) {} - - bool Append(string_view s) { - if (s.empty()) return true; - - size_t text_end = AppendText(s); - - if (!parsed->items_.empty() && !parsed->items_.back().is_conversion) { - // Let's extend the existing text run. - parsed->items_.back().text_end = text_end; - } else { - // Let's make a new text run. - parsed->items_.push_back({false, text_end, {}}); - } - return true; - } - - bool ConvertOne(const UnboundConversion &conv, string_view s) { - size_t text_end = AppendText(s); - parsed->items_.push_back({true, text_end, conv}); - return true; - } - - size_t AppendText(string_view s) { - memcpy(data_pos, s.data(), s.size()); - data_pos += s.size(); - return static_cast<size_t>(data_pos - parsed->data_.get()); - } - - ParsedFormatBase *parsed; - char* data_pos; -}; - +const char *ConsumeUnboundConversion(const char *p, const char *end, + UnboundConversion *conv, int *next_arg) { + if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg); + return ConsumeConversion<false>(p, end, conv, next_arg); +} + +struct ParsedFormatBase::ParsedFormatConsumer { + explicit ParsedFormatConsumer(ParsedFormatBase *parsedformat) + : parsed(parsedformat), data_pos(parsedformat->data_.get()) {} + + bool Append(string_view s) { + if (s.empty()) return true; + + size_t text_end = AppendText(s); + + if (!parsed->items_.empty() && !parsed->items_.back().is_conversion) { + // Let's extend the existing text run. + parsed->items_.back().text_end = text_end; + } else { + // Let's make a new text run. + parsed->items_.push_back({false, text_end, {}}); + } + return true; + } + + bool ConvertOne(const UnboundConversion &conv, string_view s) { + size_t text_end = AppendText(s); + parsed->items_.push_back({true, text_end, conv}); + return true; + } + + size_t AppendText(string_view s) { + memcpy(data_pos, s.data(), s.size()); + data_pos += s.size(); + return static_cast<size_t>(data_pos - parsed->data_.get()); + } + + ParsedFormatBase *parsed; + char* data_pos; +}; + ParsedFormatBase::ParsedFormatBase( string_view format, bool allow_ignored, std::initializer_list<FormatConversionCharSet> convs) - : data_(format.empty() ? nullptr : new char[format.size()]) { - has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) || - !MatchesConversions(allow_ignored, convs); -} - -bool ParsedFormatBase::MatchesConversions( + : data_(format.empty() ? nullptr : new char[format.size()]) { + has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) || + !MatchesConversions(allow_ignored, convs); +} + +bool ParsedFormatBase::MatchesConversions( bool allow_ignored, std::initializer_list<FormatConversionCharSet> convs) const { - std::unordered_set<int> used; - auto add_if_valid_conv = [&](int pos, char c) { - if (static_cast<size_t>(pos) > convs.size() || - !Contains(convs.begin()[pos - 1], c)) - return false; - used.insert(pos); - return true; - }; - for (const ConversionItem &item : items_) { - if (!item.is_conversion) continue; - auto &conv = item.conv; - if (conv.precision.is_from_arg() && - !add_if_valid_conv(conv.precision.get_from_arg(), '*')) - return false; - if (conv.width.is_from_arg() && - !add_if_valid_conv(conv.width.get_from_arg(), '*')) - return false; + std::unordered_set<int> used; + auto add_if_valid_conv = [&](int pos, char c) { + if (static_cast<size_t>(pos) > convs.size() || + !Contains(convs.begin()[pos - 1], c)) + return false; + used.insert(pos); + return true; + }; + for (const ConversionItem &item : items_) { + if (!item.is_conversion) continue; + auto &conv = item.conv; + if (conv.precision.is_from_arg() && + !add_if_valid_conv(conv.precision.get_from_arg(), '*')) + return false; + if (conv.width.is_from_arg() && + !add_if_valid_conv(conv.width.get_from_arg(), '*')) + return false; if (!add_if_valid_conv(conv.arg_position, FormatConversionCharToChar(conv.conv))) return false; - } - return used.size() == convs.size() || allow_ignored; -} - -} // namespace str_format_internal + } + return used.size() == convs.size() || allow_ignored; +} + +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h index ba614bb8b4..02a4792b4e 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h @@ -12,88 +12,88 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ -#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ - -#include <limits.h> -#include <stddef.h> -#include <stdlib.h> - -#include <cassert> +#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ +#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ + +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> + +#include <cassert> #include <cstdint> -#include <initializer_list> -#include <iosfwd> -#include <iterator> -#include <memory> +#include <initializer_list> +#include <iosfwd> +#include <iterator> +#include <memory> #include <util/generic/string.h> -#include <vector> - +#include <vector> + #include "y_absl/strings/internal/str_format/checker.h" #include "y_absl/strings/internal/str_format/extension.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace str_format_internal { - +namespace str_format_internal { + enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none }; TString LengthModToString(LengthMod v); -// The analyzed properties of a single specified conversion. -struct UnboundConversion { +// The analyzed properties of a single specified conversion. +struct UnboundConversion { UnboundConversion() {} - - class InputValue { - public: - void set_value(int value) { - assert(value >= 0); - value_ = value; - } - int value() const { return value_; } - - // Marks the value as "from arg". aka the '*' format. - // Requires `value >= 1`. - // When set, is_from_arg() return true and get_from_arg() returns the - // original value. - // `value()`'s return value is unspecfied in this state. - void set_from_arg(int value) { - assert(value > 0); - value_ = -value - 1; - } - bool is_from_arg() const { return value_ < -1; } - int get_from_arg() const { - assert(is_from_arg()); - return -value_ - 1; - } - - private: - int value_ = -1; - }; - - // No need to initialize. It will always be set in the parser. - int arg_position; - - InputValue width; - InputValue precision; - + + class InputValue { + public: + void set_value(int value) { + assert(value >= 0); + value_ = value; + } + int value() const { return value_; } + + // Marks the value as "from arg". aka the '*' format. + // Requires `value >= 1`. + // When set, is_from_arg() return true and get_from_arg() returns the + // original value. + // `value()`'s return value is unspecfied in this state. + void set_from_arg(int value) { + assert(value > 0); + value_ = -value - 1; + } + bool is_from_arg() const { return value_ < -1; } + int get_from_arg() const { + assert(is_from_arg()); + return -value_ - 1; + } + + private: + int value_ = -1; + }; + + // No need to initialize. It will always be set in the parser. + int arg_position; + + InputValue width; + InputValue precision; + Flags flags = Flags::kBasic; LengthMod length_mod = LengthMod::none; FormatConversionChar conv = FormatConversionCharInternal::kNone; -}; - -// Consume conversion spec prefix (not including '%') of [p, end) if valid. -// Examples of valid specs would be e.g.: "s", "d", "-12.6f". -// If valid, it returns the first character following the conversion spec, -// and the spec part is broken down and returned in 'conv'. -// If invalid, returns nullptr. -const char* ConsumeUnboundConversion(const char* p, const char* end, - UnboundConversion* conv, int* next_arg); - -// Helper tag class for the table below. +}; + +// Consume conversion spec prefix (not including '%') of [p, end) if valid. +// Examples of valid specs would be e.g.: "s", "d", "-12.6f". +// If valid, it returns the first character following the conversion spec, +// and the spec part is broken down and returned in 'conv'. +// If invalid, returns nullptr. +const char* ConsumeUnboundConversion(const char* p, const char* end, + UnboundConversion* conv, int* next_arg); + +// Helper tag class for the table below. // It allows fast `char -> ConversionChar/LengthMod/Flags` checking and // conversions. -class ConvTag { - public: +class ConvTag { + public: constexpr ConvTag(FormatConversionChar conversion_char) // NOLINT : tag_(static_cast<uint8_t>(conversion_char)) {} constexpr ConvTag(LengthMod length_mod) // NOLINT @@ -101,257 +101,257 @@ class ConvTag { constexpr ConvTag(Flags flags) // NOLINT : tag_(0xc0 | static_cast<uint8_t>(flags)) {} constexpr ConvTag() : tag_(0xFF) {} - + bool is_conv() const { return (tag_ & 0x80) == 0; } bool is_length() const { return (tag_ & 0xC0) == 0x80; } bool is_flags() const { return (tag_ & 0xE0) == 0xC0; } FormatConversionChar as_conv() const { - assert(is_conv()); + assert(is_conv()); assert(!is_length()); assert(!is_flags()); return static_cast<FormatConversionChar>(tag_); - } - LengthMod as_length() const { + } + LengthMod as_length() const { assert(!is_conv()); - assert(is_length()); + assert(is_length()); assert(!is_flags()); return static_cast<LengthMod>(tag_ & 0x3F); - } + } Flags as_flags() const { assert(!is_conv()); assert(!is_length()); assert(is_flags()); return static_cast<Flags>(tag_ & 0x1F); } - - private: + + private: uint8_t tag_; -}; - -extern const ConvTag kTags[256]; -// Keep a single table for all the conversion chars and length modifiers. -inline ConvTag GetTagForChar(char c) { - return kTags[static_cast<unsigned char>(c)]; -} - -// Parse the format string provided in 'src' and pass the identified items into -// 'consumer'. -// Text runs will be passed by calling -// Consumer::Append(string_view); -// ConversionItems will be passed by calling -// Consumer::ConvertOne(UnboundConversion, string_view); -// In the case of ConvertOne, the string_view that is passed is the -// portion of the format string corresponding to the conversion, not including -// the leading %. On success, it returns true. On failure, it stops and returns -// false. -template <typename Consumer> -bool ParseFormatString(string_view src, Consumer consumer) { - int next_arg = 0; - const char* p = src.data(); - const char* const end = p + src.size(); - while (p != end) { - const char* percent = static_cast<const char*>(memchr(p, '%', end - p)); - if (!percent) { - // We found the last substring. - return consumer.Append(string_view(p, end - p)); - } - // We found a percent, so push the text run then process the percent. - if (ABSL_PREDICT_FALSE(!consumer.Append(string_view(p, percent - p)))) { - return false; - } - if (ABSL_PREDICT_FALSE(percent + 1 >= end)) return false; - - auto tag = GetTagForChar(percent[1]); - if (tag.is_conv()) { - if (ABSL_PREDICT_FALSE(next_arg < 0)) { +}; + +extern const ConvTag kTags[256]; +// Keep a single table for all the conversion chars and length modifiers. +inline ConvTag GetTagForChar(char c) { + return kTags[static_cast<unsigned char>(c)]; +} + +// Parse the format string provided in 'src' and pass the identified items into +// 'consumer'. +// Text runs will be passed by calling +// Consumer::Append(string_view); +// ConversionItems will be passed by calling +// Consumer::ConvertOne(UnboundConversion, string_view); +// In the case of ConvertOne, the string_view that is passed is the +// portion of the format string corresponding to the conversion, not including +// the leading %. On success, it returns true. On failure, it stops and returns +// false. +template <typename Consumer> +bool ParseFormatString(string_view src, Consumer consumer) { + int next_arg = 0; + const char* p = src.data(); + const char* const end = p + src.size(); + while (p != end) { + const char* percent = static_cast<const char*>(memchr(p, '%', end - p)); + if (!percent) { + // We found the last substring. + return consumer.Append(string_view(p, end - p)); + } + // We found a percent, so push the text run then process the percent. + if (ABSL_PREDICT_FALSE(!consumer.Append(string_view(p, percent - p)))) { + return false; + } + if (ABSL_PREDICT_FALSE(percent + 1 >= end)) return false; + + auto tag = GetTagForChar(percent[1]); + if (tag.is_conv()) { + if (ABSL_PREDICT_FALSE(next_arg < 0)) { // This indicates an error in the format string. - // The only way to get `next_arg < 0` here is to have a positional - // argument first which sets next_arg to -1 and then a non-positional - // argument. - return false; - } - p = percent + 2; - - // Keep this case separate from the one below. - // ConvertOne is more efficient when the compiler can see that the `basic` - // flag is set. - UnboundConversion conv; - conv.conv = tag.as_conv(); - conv.arg_position = ++next_arg; - if (ABSL_PREDICT_FALSE( - !consumer.ConvertOne(conv, string_view(percent + 1, 1)))) { - return false; - } - } else if (percent[1] != '%') { - UnboundConversion conv; - p = ConsumeUnboundConversion(percent + 1, end, &conv, &next_arg); - if (ABSL_PREDICT_FALSE(p == nullptr)) return false; - if (ABSL_PREDICT_FALSE(!consumer.ConvertOne( - conv, string_view(percent + 1, p - (percent + 1))))) { - return false; - } - } else { - if (ABSL_PREDICT_FALSE(!consumer.Append("%"))) return false; - p = percent + 2; - continue; - } - } - return true; -} - -// Always returns true, or fails to compile in a constexpr context if s does not -// point to a constexpr char array. -constexpr bool EnsureConstexpr(string_view s) { - return s.empty() || s[0] == s[0]; -} - -class ParsedFormatBase { - public: + // The only way to get `next_arg < 0` here is to have a positional + // argument first which sets next_arg to -1 and then a non-positional + // argument. + return false; + } + p = percent + 2; + + // Keep this case separate from the one below. + // ConvertOne is more efficient when the compiler can see that the `basic` + // flag is set. + UnboundConversion conv; + conv.conv = tag.as_conv(); + conv.arg_position = ++next_arg; + if (ABSL_PREDICT_FALSE( + !consumer.ConvertOne(conv, string_view(percent + 1, 1)))) { + return false; + } + } else if (percent[1] != '%') { + UnboundConversion conv; + p = ConsumeUnboundConversion(percent + 1, end, &conv, &next_arg); + if (ABSL_PREDICT_FALSE(p == nullptr)) return false; + if (ABSL_PREDICT_FALSE(!consumer.ConvertOne( + conv, string_view(percent + 1, p - (percent + 1))))) { + return false; + } + } else { + if (ABSL_PREDICT_FALSE(!consumer.Append("%"))) return false; + p = percent + 2; + continue; + } + } + return true; +} + +// Always returns true, or fails to compile in a constexpr context if s does not +// point to a constexpr char array. +constexpr bool EnsureConstexpr(string_view s) { + return s.empty() || s[0] == s[0]; +} + +class ParsedFormatBase { + public: explicit ParsedFormatBase( string_view format, bool allow_ignored, std::initializer_list<FormatConversionCharSet> convs); - - ParsedFormatBase(const ParsedFormatBase& other) { *this = other; } - - ParsedFormatBase(ParsedFormatBase&& other) { *this = std::move(other); } - - ParsedFormatBase& operator=(const ParsedFormatBase& other) { - if (this == &other) return *this; - has_error_ = other.has_error_; - items_ = other.items_; - size_t text_size = items_.empty() ? 0 : items_.back().text_end; - data_.reset(new char[text_size]); - memcpy(data_.get(), other.data_.get(), text_size); - return *this; - } - - ParsedFormatBase& operator=(ParsedFormatBase&& other) { - if (this == &other) return *this; - has_error_ = other.has_error_; - data_ = std::move(other.data_); - items_ = std::move(other.items_); - // Reset the vector to make sure the invariants hold. - other.items_.clear(); - return *this; - } - - template <typename Consumer> - bool ProcessFormat(Consumer consumer) const { - const char* const base = data_.get(); - string_view text(base, 0); - for (const auto& item : items_) { - const char* const end = text.data() + text.size(); - text = string_view(end, (base + item.text_end) - end); - if (item.is_conversion) { - if (!consumer.ConvertOne(item.conv, text)) return false; - } else { - if (!consumer.Append(text)) return false; - } - } - return !has_error_; - } - - bool has_error() const { return has_error_; } - - private: - // Returns whether the conversions match and if !allow_ignored it verifies - // that all conversions are used by the format. + + ParsedFormatBase(const ParsedFormatBase& other) { *this = other; } + + ParsedFormatBase(ParsedFormatBase&& other) { *this = std::move(other); } + + ParsedFormatBase& operator=(const ParsedFormatBase& other) { + if (this == &other) return *this; + has_error_ = other.has_error_; + items_ = other.items_; + size_t text_size = items_.empty() ? 0 : items_.back().text_end; + data_.reset(new char[text_size]); + memcpy(data_.get(), other.data_.get(), text_size); + return *this; + } + + ParsedFormatBase& operator=(ParsedFormatBase&& other) { + if (this == &other) return *this; + has_error_ = other.has_error_; + data_ = std::move(other.data_); + items_ = std::move(other.items_); + // Reset the vector to make sure the invariants hold. + other.items_.clear(); + return *this; + } + + template <typename Consumer> + bool ProcessFormat(Consumer consumer) const { + const char* const base = data_.get(); + string_view text(base, 0); + for (const auto& item : items_) { + const char* const end = text.data() + text.size(); + text = string_view(end, (base + item.text_end) - end); + if (item.is_conversion) { + if (!consumer.ConvertOne(item.conv, text)) return false; + } else { + if (!consumer.Append(text)) return false; + } + } + return !has_error_; + } + + bool has_error() const { return has_error_; } + + private: + // Returns whether the conversions match and if !allow_ignored it verifies + // that all conversions are used by the format. bool MatchesConversions( bool allow_ignored, std::initializer_list<FormatConversionCharSet> convs) const; - - struct ParsedFormatConsumer; - - struct ConversionItem { - bool is_conversion; - // Points to the past-the-end location of this element in the data_ array. - size_t text_end; - UnboundConversion conv; - }; - - bool has_error_; - std::unique_ptr<char[]> data_; - std::vector<ConversionItem> items_; -}; - - -// A value type representing a preparsed format. These can be created, copied -// around, and reused to speed up formatting loops. -// The user must specify through the template arguments the conversion -// characters used in the format. This will be checked at compile time. -// -// This class uses Conv enum values to specify each argument. -// This allows for more flexibility as you can specify multiple possible -// conversion characters for each argument. -// ParsedFormat<char...> is a simplified alias for when the user only -// needs to specify a single conversion character for each argument. -// -// Example: -// // Extended format supports multiple characters per argument: -// using MyFormat = ExtendedParsedFormat<Conv::d | Conv::x>; -// MyFormat GetFormat(bool use_hex) { -// if (use_hex) return MyFormat("foo %x bar"); -// return MyFormat("foo %d bar"); -// } -// // 'format' can be used with any value that supports 'd' and 'x', -// // like `int`. -// auto format = GetFormat(use_hex); -// value = StringF(format, i); -// -// This class also supports runtime format checking with the ::New() and -// ::NewAllowIgnored() factory functions. -// This is the only API that allows the user to pass a runtime specified format -// string. These factory functions will return NULL if the format does not match -// the conversions requested by the user. + + struct ParsedFormatConsumer; + + struct ConversionItem { + bool is_conversion; + // Points to the past-the-end location of this element in the data_ array. + size_t text_end; + UnboundConversion conv; + }; + + bool has_error_; + std::unique_ptr<char[]> data_; + std::vector<ConversionItem> items_; +}; + + +// A value type representing a preparsed format. These can be created, copied +// around, and reused to speed up formatting loops. +// The user must specify through the template arguments the conversion +// characters used in the format. This will be checked at compile time. +// +// This class uses Conv enum values to specify each argument. +// This allows for more flexibility as you can specify multiple possible +// conversion characters for each argument. +// ParsedFormat<char...> is a simplified alias for when the user only +// needs to specify a single conversion character for each argument. +// +// Example: +// // Extended format supports multiple characters per argument: +// using MyFormat = ExtendedParsedFormat<Conv::d | Conv::x>; +// MyFormat GetFormat(bool use_hex) { +// if (use_hex) return MyFormat("foo %x bar"); +// return MyFormat("foo %d bar"); +// } +// // 'format' can be used with any value that supports 'd' and 'x', +// // like `int`. +// auto format = GetFormat(use_hex); +// value = StringF(format, i); +// +// This class also supports runtime format checking with the ::New() and +// ::NewAllowIgnored() factory functions. +// This is the only API that allows the user to pass a runtime specified format +// string. These factory functions will return NULL if the format does not match +// the conversions requested by the user. template <FormatConversionCharSet... C> -class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase { - public: - explicit ExtendedParsedFormat(string_view format) +class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase { + public: + explicit ExtendedParsedFormat(string_view format) #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - __attribute__(( - enable_if(str_format_internal::EnsureConstexpr(format), + __attribute__(( + enable_if(str_format_internal::EnsureConstexpr(format), "Format string is not constexpr."), - enable_if(str_format_internal::ValidFormatImpl<C...>(format), - "Format specified does not match the template arguments."))) -#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - : ExtendedParsedFormat(format, false) { - } - - // ExtendedParsedFormat factory function. - // The user still has to specify the conversion characters, but they will not - // be checked at compile time. Instead, it will be checked at runtime. - // This delays the checking to runtime, but allows the user to pass - // dynamically sourced formats. - // It returns NULL if the format does not match the conversion characters. - // The user is responsible for checking the return value before using it. - // - // The 'New' variant will check that all the specified arguments are being - // consumed by the format and return NULL if any argument is being ignored. - // The 'NewAllowIgnored' variant will not verify this and will allow formats - // that ignore arguments. - static std::unique_ptr<ExtendedParsedFormat> New(string_view format) { - return New(format, false); - } - static std::unique_ptr<ExtendedParsedFormat> NewAllowIgnored( - string_view format) { - return New(format, true); - } - - private: - static std::unique_ptr<ExtendedParsedFormat> New(string_view format, - bool allow_ignored) { - std::unique_ptr<ExtendedParsedFormat> conv( - new ExtendedParsedFormat(format, allow_ignored)); - if (conv->has_error()) return nullptr; - return conv; - } - - ExtendedParsedFormat(string_view s, bool allow_ignored) - : ParsedFormatBase(s, allow_ignored, {C...}) {} -}; -} // namespace str_format_internal + enable_if(str_format_internal::ValidFormatImpl<C...>(format), + "Format specified does not match the template arguments."))) +#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER + : ExtendedParsedFormat(format, false) { + } + + // ExtendedParsedFormat factory function. + // The user still has to specify the conversion characters, but they will not + // be checked at compile time. Instead, it will be checked at runtime. + // This delays the checking to runtime, but allows the user to pass + // dynamically sourced formats. + // It returns NULL if the format does not match the conversion characters. + // The user is responsible for checking the return value before using it. + // + // The 'New' variant will check that all the specified arguments are being + // consumed by the format and return NULL if any argument is being ignored. + // The 'NewAllowIgnored' variant will not verify this and will allow formats + // that ignore arguments. + static std::unique_ptr<ExtendedParsedFormat> New(string_view format) { + return New(format, false); + } + static std::unique_ptr<ExtendedParsedFormat> NewAllowIgnored( + string_view format) { + return New(format, true); + } + + private: + static std::unique_ptr<ExtendedParsedFormat> New(string_view format, + bool allow_ignored) { + std::unique_ptr<ExtendedParsedFormat> conv( + new ExtendedParsedFormat(format, allow_ignored)); + if (conv->has_error()) return nullptr; + return conv; + } + + ExtendedParsedFormat(string_view s, bool allow_ignored) + : ParsedFormatBase(s, allow_ignored, {C...}) {} +}; +} // namespace str_format_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make index ff8069cd0f..aabeb54a28 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make @@ -1,17 +1,17 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( somov g:cpp-contrib ) - -LICENSE(Apache-2.0) - + +LICENSE(Apache-2.0) + LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait @@ -20,21 +20,21 @@ PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/numeric contrib/restricted/abseil-cpp-tstring/y_absl/strings contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal -) - +) + ADDINCL( GLOBAL contrib/restricted/abseil-cpp-tstring ) - -NO_COMPILER_WARNINGS() - -SRCS( - arg.cc - bind.cc - extension.cc - float_conversion.cc - output.cc - parser.cc -) - -END() + +NO_COMPILER_WARNINGS() + +SRCS( + arg.cc + bind.cc + extension.cc + float_conversion.cc + output.cc + parser.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_join_internal.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_join_internal.h index 0a220fa33d..32f114807a 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_join_internal.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_join_internal.h @@ -1,314 +1,314 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// This file declares INTERNAL parts of the Join API that are inlined/templated -// or otherwise need to be available at compile time. The main abstractions -// defined in this file are: -// -// - A handful of default Formatters -// - JoinAlgorithm() overloads -// - JoinRange() overloads -// - JoinTuple() -// -// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// This file declares INTERNAL parts of the Join API that are inlined/templated +// or otherwise need to be available at compile time. The main abstractions +// defined in this file are: +// +// - A handful of default Formatters +// - JoinAlgorithm() overloads +// - JoinRange() overloads +// - JoinTuple() +// +// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including // y_absl/strings/str_join.h -// +// // IWYU pragma: private, include "y_absl/strings/str_join.h" - -#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ -#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ - -#include <cstring> -#include <iterator> -#include <memory> + +#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ +#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ + +#include <cstring> +#include <iterator> +#include <memory> #include <util/generic/string.h> -#include <type_traits> -#include <utility> - +#include <type_traits> +#include <utility> + #include "y_absl/strings/internal/ostringstream.h" #include "y_absl/strings/internal/resize_uninitialized.h" #include "y_absl/strings/str_cat.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -// -// Formatter objects -// -// The following are implementation classes for standard Formatter objects. The -// factory functions that users will call to create and use these formatters are -// defined and documented in strings/join.h. -// - -// The default formatter. Converts alpha-numeric types to strings. -struct AlphaNumFormatterImpl { - // This template is needed in order to support passing in a dereferenced - // vector<bool>::iterator - template <typename T> +namespace strings_internal { + +// +// Formatter objects +// +// The following are implementation classes for standard Formatter objects. The +// factory functions that users will call to create and use these formatters are +// defined and documented in strings/join.h. +// + +// The default formatter. Converts alpha-numeric types to strings. +struct AlphaNumFormatterImpl { + // This template is needed in order to support passing in a dereferenced + // vector<bool>::iterator + template <typename T> void operator()(TString* out, const T& t) const { - StrAppend(out, AlphaNum(t)); - } - + StrAppend(out, AlphaNum(t)); + } + void operator()(TString* out, const AlphaNum& t) const { - StrAppend(out, t); - } -}; - -// A type that's used to overload the JoinAlgorithm() function (defined below) -// for ranges that do not require additional formatting (e.g., a range of -// strings). - -struct NoFormatter : public AlphaNumFormatterImpl {}; - -// Formats types to strings using the << operator. -class StreamFormatterImpl { - public: - // The method isn't const because it mutates state. Making it const will - // render StreamFormatterImpl thread-hostile. - template <typename T> + StrAppend(out, t); + } +}; + +// A type that's used to overload the JoinAlgorithm() function (defined below) +// for ranges that do not require additional formatting (e.g., a range of +// strings). + +struct NoFormatter : public AlphaNumFormatterImpl {}; + +// Formats types to strings using the << operator. +class StreamFormatterImpl { + public: + // The method isn't const because it mutates state. Making it const will + // render StreamFormatterImpl thread-hostile. + template <typename T> void operator()(TString* out, const T& t) { - // The stream is created lazily to avoid paying the relatively high cost - // of its construction when joining an empty range. - if (strm_) { - strm_->clear(); // clear the bad, fail and eof bits in case they were set - strm_->str(out); - } else { - strm_.reset(new strings_internal::OStringStream(out)); - } - *strm_ << t; - } - - private: - std::unique_ptr<strings_internal::OStringStream> strm_; -}; - -// Formats a std::pair<>. The 'first' member is formatted using f1_ and the -// 'second' member is formatted using f2_. sep_ is the separator. -template <typename F1, typename F2> -class PairFormatterImpl { - public: + // The stream is created lazily to avoid paying the relatively high cost + // of its construction when joining an empty range. + if (strm_) { + strm_->clear(); // clear the bad, fail and eof bits in case they were set + strm_->str(out); + } else { + strm_.reset(new strings_internal::OStringStream(out)); + } + *strm_ << t; + } + + private: + std::unique_ptr<strings_internal::OStringStream> strm_; +}; + +// Formats a std::pair<>. The 'first' member is formatted using f1_ and the +// 'second' member is formatted using f2_. sep_ is the separator. +template <typename F1, typename F2> +class PairFormatterImpl { + public: PairFormatterImpl(F1 f1, y_absl::string_view sep, F2 f2) - : f1_(std::move(f1)), sep_(sep), f2_(std::move(f2)) {} - - template <typename T> + : f1_(std::move(f1)), sep_(sep), f2_(std::move(f2)) {} + + template <typename T> void operator()(TString* out, const T& p) { - f1_(out, p.first); - out->append(sep_); - f2_(out, p.second); - } - - template <typename T> + f1_(out, p.first); + out->append(sep_); + f2_(out, p.second); + } + + template <typename T> void operator()(TString* out, const T& p) const { - f1_(out, p.first); - out->append(sep_); - f2_(out, p.second); - } - - private: - F1 f1_; + f1_(out, p.first); + out->append(sep_); + f2_(out, p.second); + } + + private: + F1 f1_; TString sep_; - F2 f2_; -}; - -// Wraps another formatter and dereferences the argument to operator() then -// passes the dereferenced argument to the wrapped formatter. This can be -// useful, for example, to join a std::vector<int*>. -template <typename Formatter> -class DereferenceFormatterImpl { - public: - DereferenceFormatterImpl() : f_() {} - explicit DereferenceFormatterImpl(Formatter&& f) - : f_(std::forward<Formatter>(f)) {} - - template <typename T> + F2 f2_; +}; + +// Wraps another formatter and dereferences the argument to operator() then +// passes the dereferenced argument to the wrapped formatter. This can be +// useful, for example, to join a std::vector<int*>. +template <typename Formatter> +class DereferenceFormatterImpl { + public: + DereferenceFormatterImpl() : f_() {} + explicit DereferenceFormatterImpl(Formatter&& f) + : f_(std::forward<Formatter>(f)) {} + + template <typename T> void operator()(TString* out, const T& t) { - f_(out, *t); - } - - template <typename T> + f_(out, *t); + } + + template <typename T> void operator()(TString* out, const T& t) const { - f_(out, *t); - } - - private: - Formatter f_; -}; - -// DefaultFormatter<T> is a traits class that selects a default Formatter to use -// for the given type T. The ::Type member names the Formatter to use. This is -// used by the strings::Join() functions that do NOT take a Formatter argument, -// in which case a default Formatter must be chosen. -// -// AlphaNumFormatterImpl is the default in the base template, followed by -// specializations for other types. -template <typename ValueType> -struct DefaultFormatter { - typedef AlphaNumFormatterImpl Type; -}; -template <> -struct DefaultFormatter<const char*> { - typedef AlphaNumFormatterImpl Type; -}; -template <> -struct DefaultFormatter<char*> { - typedef AlphaNumFormatterImpl Type; -}; -template <> + f_(out, *t); + } + + private: + Formatter f_; +}; + +// DefaultFormatter<T> is a traits class that selects a default Formatter to use +// for the given type T. The ::Type member names the Formatter to use. This is +// used by the strings::Join() functions that do NOT take a Formatter argument, +// in which case a default Formatter must be chosen. +// +// AlphaNumFormatterImpl is the default in the base template, followed by +// specializations for other types. +template <typename ValueType> +struct DefaultFormatter { + typedef AlphaNumFormatterImpl Type; +}; +template <> +struct DefaultFormatter<const char*> { + typedef AlphaNumFormatterImpl Type; +}; +template <> +struct DefaultFormatter<char*> { + typedef AlphaNumFormatterImpl Type; +}; +template <> struct DefaultFormatter<TString> { - typedef NoFormatter Type; -}; -template <> + typedef NoFormatter Type; +}; +template <> struct DefaultFormatter<y_absl::string_view> { - typedef NoFormatter Type; -}; -template <typename ValueType> -struct DefaultFormatter<ValueType*> { - typedef DereferenceFormatterImpl<typename DefaultFormatter<ValueType>::Type> - Type; -}; - -template <typename ValueType> -struct DefaultFormatter<std::unique_ptr<ValueType>> - : public DefaultFormatter<ValueType*> {}; - -// -// JoinAlgorithm() functions -// - -// The main joining algorithm. This simply joins the elements in the given -// iterator range, each separated by the given separator, into an output string, -// and formats each element using the provided Formatter object. -template <typename Iterator, typename Formatter> + typedef NoFormatter Type; +}; +template <typename ValueType> +struct DefaultFormatter<ValueType*> { + typedef DereferenceFormatterImpl<typename DefaultFormatter<ValueType>::Type> + Type; +}; + +template <typename ValueType> +struct DefaultFormatter<std::unique_ptr<ValueType>> + : public DefaultFormatter<ValueType*> {}; + +// +// JoinAlgorithm() functions +// + +// The main joining algorithm. This simply joins the elements in the given +// iterator range, each separated by the given separator, into an output string, +// and formats each element using the provided Formatter object. +template <typename Iterator, typename Formatter> TString JoinAlgorithm(Iterator start, Iterator end, y_absl::string_view s, - Formatter&& f) { + Formatter&& f) { TString result; y_absl::string_view sep(""); - for (Iterator it = start; it != end; ++it) { - result.append(sep.data(), sep.size()); - f(&result, *it); - sep = s; - } - return result; -} - -// A joining algorithm that's optimized for a forward iterator range of -// string-like objects that do not need any additional formatting. This is to -// optimize the common case of joining, say, a std::vector<string> or a + for (Iterator it = start; it != end; ++it) { + result.append(sep.data(), sep.size()); + f(&result, *it); + sep = s; + } + return result; +} + +// A joining algorithm that's optimized for a forward iterator range of +// string-like objects that do not need any additional formatting. This is to +// optimize the common case of joining, say, a std::vector<string> or a // std::vector<y_absl::string_view>. -// -// This is an overload of the previous JoinAlgorithm() function. Here the -// Formatter argument is of type NoFormatter. Since NoFormatter is an internal -// type, this overload is only invoked when strings::Join() is called with a +// +// This is an overload of the previous JoinAlgorithm() function. Here the +// Formatter argument is of type NoFormatter. Since NoFormatter is an internal +// type, this overload is only invoked when strings::Join() is called with a // range of string-like objects (e.g., TString, y_absl::string_view), and an -// explicit Formatter argument was NOT specified. -// -// The optimization is that the needed space will be reserved in the output -// string to avoid the need to resize while appending. To do this, the iterator -// range will be traversed twice: once to calculate the total needed size, and -// then again to copy the elements and delimiters to the output string. -template <typename Iterator, - typename = typename std::enable_if<std::is_convertible< - typename std::iterator_traits<Iterator>::iterator_category, - std::forward_iterator_tag>::value>::type> +// explicit Formatter argument was NOT specified. +// +// The optimization is that the needed space will be reserved in the output +// string to avoid the need to resize while appending. To do this, the iterator +// range will be traversed twice: once to calculate the total needed size, and +// then again to copy the elements and delimiters to the output string. +template <typename Iterator, + typename = typename std::enable_if<std::is_convertible< + typename std::iterator_traits<Iterator>::iterator_category, + std::forward_iterator_tag>::value>::type> TString JoinAlgorithm(Iterator start, Iterator end, y_absl::string_view s, - NoFormatter) { + NoFormatter) { TString result; - if (start != end) { - // Sums size - size_t result_size = start->size(); - for (Iterator it = start; ++it != end;) { - result_size += s.size(); - result_size += it->size(); - } - - if (result_size > 0) { - STLStringResizeUninitialized(&result, result_size); - - // Joins strings - char* result_buf = &*result.begin(); - memcpy(result_buf, start->data(), start->size()); - result_buf += start->size(); - for (Iterator it = start; ++it != end;) { - memcpy(result_buf, s.data(), s.size()); - result_buf += s.size(); - memcpy(result_buf, it->data(), it->size()); - result_buf += it->size(); - } - } - } - - return result; -} - -// JoinTupleLoop implements a loop over the elements of a std::tuple, which -// are heterogeneous. The primary template matches the tuple interior case. It -// continues the iteration after appending a separator (for nonzero indices) -// and formatting an element of the tuple. The specialization for the I=N case -// matches the end-of-tuple, and terminates the iteration. -template <size_t I, size_t N> -struct JoinTupleLoop { - template <typename Tup, typename Formatter> + if (start != end) { + // Sums size + size_t result_size = start->size(); + for (Iterator it = start; ++it != end;) { + result_size += s.size(); + result_size += it->size(); + } + + if (result_size > 0) { + STLStringResizeUninitialized(&result, result_size); + + // Joins strings + char* result_buf = &*result.begin(); + memcpy(result_buf, start->data(), start->size()); + result_buf += start->size(); + for (Iterator it = start; ++it != end;) { + memcpy(result_buf, s.data(), s.size()); + result_buf += s.size(); + memcpy(result_buf, it->data(), it->size()); + result_buf += it->size(); + } + } + } + + return result; +} + +// JoinTupleLoop implements a loop over the elements of a std::tuple, which +// are heterogeneous. The primary template matches the tuple interior case. It +// continues the iteration after appending a separator (for nonzero indices) +// and formatting an element of the tuple. The specialization for the I=N case +// matches the end-of-tuple, and terminates the iteration. +template <size_t I, size_t N> +struct JoinTupleLoop { + template <typename Tup, typename Formatter> void operator()(TString* out, const Tup& tup, y_absl::string_view sep, - Formatter&& fmt) { - if (I > 0) out->append(sep.data(), sep.size()); - fmt(out, std::get<I>(tup)); - JoinTupleLoop<I + 1, N>()(out, tup, sep, fmt); - } -}; -template <size_t N> -struct JoinTupleLoop<N, N> { - template <typename Tup, typename Formatter> + Formatter&& fmt) { + if (I > 0) out->append(sep.data(), sep.size()); + fmt(out, std::get<I>(tup)); + JoinTupleLoop<I + 1, N>()(out, tup, sep, fmt); + } +}; +template <size_t N> +struct JoinTupleLoop<N, N> { + template <typename Tup, typename Formatter> void operator()(TString*, const Tup&, y_absl::string_view, Formatter&&) {} -}; - -template <typename... T, typename Formatter> +}; + +template <typename... T, typename Formatter> TString JoinAlgorithm(const std::tuple<T...>& tup, y_absl::string_view sep, - Formatter&& fmt) { + Formatter&& fmt) { TString result; - JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt); - return result; -} - -template <typename Iterator> + JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt); + return result; +} + +template <typename Iterator> TString JoinRange(Iterator first, Iterator last, y_absl::string_view separator) { - // No formatter was explicitly given, so a default must be chosen. - typedef typename std::iterator_traits<Iterator>::value_type ValueType; - typedef typename DefaultFormatter<ValueType>::Type Formatter; - return JoinAlgorithm(first, last, separator, Formatter()); -} - -template <typename Range, typename Formatter> + // No formatter was explicitly given, so a default must be chosen. + typedef typename std::iterator_traits<Iterator>::value_type ValueType; + typedef typename DefaultFormatter<ValueType>::Type Formatter; + return JoinAlgorithm(first, last, separator, Formatter()); +} + +template <typename Range, typename Formatter> TString JoinRange(const Range& range, y_absl::string_view separator, - Formatter&& fmt) { - using std::begin; - using std::end; - return JoinAlgorithm(begin(range), end(range), separator, fmt); -} - -template <typename Range> + Formatter&& fmt) { + using std::begin; + using std::end; + return JoinAlgorithm(begin(range), end(range), separator, fmt); +} + +template <typename Range> TString JoinRange(const Range& range, y_absl::string_view separator) { - using std::begin; - using std::end; - return JoinRange(begin(range), end(range), separator); -} - -} // namespace strings_internal + using std::begin; + using std::end; + return JoinRange(begin(range), end(range), separator); +} + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h index 237864c0ed..14f93e8e98 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h @@ -1,187 +1,187 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// This file declares INTERNAL parts of the Split API that are inline/templated -// or otherwise need to be available at compile time. The main abstractions -// defined in here are -// -// - ConvertibleToStringView -// - SplitIterator<> -// - Splitter<> -// -// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// This file declares INTERNAL parts of the Split API that are inline/templated +// or otherwise need to be available at compile time. The main abstractions +// defined in here are +// +// - ConvertibleToStringView +// - SplitIterator<> +// - Splitter<> +// +// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including // y_absl/strings/str_split.h. -// +// // IWYU pragma: private, include "y_absl/strings/str_split.h" - -#ifndef ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ -#define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ - -#include <array> -#include <initializer_list> -#include <iterator> + +#ifndef ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ +#define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ + +#include <array> +#include <initializer_list> +#include <iterator> #include <tuple> -#include <type_traits> -#include <utility> -#include <vector> - +#include <type_traits> +#include <utility> +#include <vector> + #include "y_absl/base/macros.h" #include "y_absl/base/port.h" #include "y_absl/meta/type_traits.h" #include "y_absl/strings/string_view.h" - -#ifdef _GLIBCXX_DEBUG + +#ifdef _GLIBCXX_DEBUG #include "y_absl/strings/internal/stl_type_traits.h" -#endif // _GLIBCXX_DEBUG - +#endif // _GLIBCXX_DEBUG + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - +namespace strings_internal { + // This class is implicitly constructible from everything that y_absl::string_view // is implicitly constructible from, except for rvalue strings. This means it // can be used as a function parameter in places where passing a temporary // string might cause memory lifetime issues. -class ConvertibleToStringView { - public: - ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit) - : value_(s) {} - ConvertibleToStringView(char* s) : value_(s) {} // NOLINT(runtime/explicit) +class ConvertibleToStringView { + public: + ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit) + : value_(s) {} + ConvertibleToStringView(char* s) : value_(s) {} // NOLINT(runtime/explicit) ConvertibleToStringView(y_absl::string_view s) // NOLINT(runtime/explicit) - : value_(s) {} + : value_(s) {} ConvertibleToStringView(const TString& s) // NOLINT(runtime/explicit) - : value_(s) {} - + : value_(s) {} + // Disable conversion from rvalue strings. ConvertibleToStringView(TString&& s) = delete; ConvertibleToStringView(const TString&& s) = delete; - + y_absl::string_view value() const { return value_; } - - private: + + private: y_absl::string_view value_; -}; - -// An iterator that enumerates the parts of a string from a Splitter. The text -// to be split, the Delimiter, and the Predicate are all taken from the given -// Splitter object. Iterators may only be compared if they refer to the same -// Splitter instance. -// -// This class is NOT part of the public splitting API. -template <typename Splitter> -class SplitIterator { - public: - using iterator_category = std::input_iterator_tag; +}; + +// An iterator that enumerates the parts of a string from a Splitter. The text +// to be split, the Delimiter, and the Predicate are all taken from the given +// Splitter object. Iterators may only be compared if they refer to the same +// Splitter instance. +// +// This class is NOT part of the public splitting API. +template <typename Splitter> +class SplitIterator { + public: + using iterator_category = std::input_iterator_tag; using value_type = y_absl::string_view; - using difference_type = ptrdiff_t; - using pointer = const value_type*; - using reference = const value_type&; - - enum State { kInitState, kLastState, kEndState }; - SplitIterator(State state, const Splitter* splitter) - : pos_(0), - state_(state), - splitter_(splitter), - delimiter_(splitter->delimiter()), - predicate_(splitter->predicate()) { - // Hack to maintain backward compatibility. This one block makes it so an + using difference_type = ptrdiff_t; + using pointer = const value_type*; + using reference = const value_type&; + + enum State { kInitState, kLastState, kEndState }; + SplitIterator(State state, const Splitter* splitter) + : pos_(0), + state_(state), + splitter_(splitter), + delimiter_(splitter->delimiter()), + predicate_(splitter->predicate()) { + // Hack to maintain backward compatibility. This one block makes it so an // empty y_absl::string_view whose .data() happens to be nullptr behaves // *differently* from an otherwise empty y_absl::string_view whose .data() is - // not nullptr. This is an undesirable difference in general, but this - // behavior is maintained to avoid breaking existing code that happens to - // depend on this old behavior/bug. Perhaps it will be fixed one day. The - // difference in behavior is as follows: + // not nullptr. This is an undesirable difference in general, but this + // behavior is maintained to avoid breaking existing code that happens to + // depend on this old behavior/bug. Perhaps it will be fixed one day. The + // difference in behavior is as follows: // Split(y_absl::string_view(""), '-'); // {""} // Split(y_absl::string_view(), '-'); // {} - if (splitter_->text().data() == nullptr) { - state_ = kEndState; - pos_ = splitter_->text().size(); - return; - } - - if (state_ == kEndState) { - pos_ = splitter_->text().size(); - } else { - ++(*this); - } - } - - bool at_end() const { return state_ == kEndState; } - - reference operator*() const { return curr_; } - pointer operator->() const { return &curr_; } - - SplitIterator& operator++() { - do { - if (state_ == kLastState) { - state_ = kEndState; - return *this; - } + if (splitter_->text().data() == nullptr) { + state_ = kEndState; + pos_ = splitter_->text().size(); + return; + } + + if (state_ == kEndState) { + pos_ = splitter_->text().size(); + } else { + ++(*this); + } + } + + bool at_end() const { return state_ == kEndState; } + + reference operator*() const { return curr_; } + pointer operator->() const { return &curr_; } + + SplitIterator& operator++() { + do { + if (state_ == kLastState) { + state_ = kEndState; + return *this; + } const y_absl::string_view text = splitter_->text(); const y_absl::string_view d = delimiter_.Find(text, pos_); - if (d.data() == text.data() + text.size()) state_ = kLastState; - curr_ = text.substr(pos_, d.data() - (text.data() + pos_)); - pos_ += curr_.size() + d.size(); - } while (!predicate_(curr_)); - return *this; - } - - SplitIterator operator++(int) { - SplitIterator old(*this); - ++(*this); - return old; - } - - friend bool operator==(const SplitIterator& a, const SplitIterator& b) { - return a.state_ == b.state_ && a.pos_ == b.pos_; - } - - friend bool operator!=(const SplitIterator& a, const SplitIterator& b) { - return !(a == b); - } - - private: - size_t pos_; - State state_; + if (d.data() == text.data() + text.size()) state_ = kLastState; + curr_ = text.substr(pos_, d.data() - (text.data() + pos_)); + pos_ += curr_.size() + d.size(); + } while (!predicate_(curr_)); + return *this; + } + + SplitIterator operator++(int) { + SplitIterator old(*this); + ++(*this); + return old; + } + + friend bool operator==(const SplitIterator& a, const SplitIterator& b) { + return a.state_ == b.state_ && a.pos_ == b.pos_; + } + + friend bool operator!=(const SplitIterator& a, const SplitIterator& b) { + return !(a == b); + } + + private: + size_t pos_; + State state_; y_absl::string_view curr_; - const Splitter* splitter_; - typename Splitter::DelimiterType delimiter_; - typename Splitter::PredicateType predicate_; -}; - -// HasMappedType<T>::value is true iff there exists a type T::mapped_type. -template <typename T, typename = void> -struct HasMappedType : std::false_type {}; -template <typename T> + const Splitter* splitter_; + typename Splitter::DelimiterType delimiter_; + typename Splitter::PredicateType predicate_; +}; + +// HasMappedType<T>::value is true iff there exists a type T::mapped_type. +template <typename T, typename = void> +struct HasMappedType : std::false_type {}; +template <typename T> struct HasMappedType<T, y_absl::void_t<typename T::mapped_type>> - : std::true_type {}; - -// HasValueType<T>::value is true iff there exists a type T::value_type. -template <typename T, typename = void> -struct HasValueType : std::false_type {}; -template <typename T> + : std::true_type {}; + +// HasValueType<T>::value is true iff there exists a type T::value_type. +template <typename T, typename = void> +struct HasValueType : std::false_type {}; +template <typename T> struct HasValueType<T, y_absl::void_t<typename T::value_type>> : std::true_type { -}; - -// HasConstIterator<T>::value is true iff there exists a type T::const_iterator. -template <typename T, typename = void> -struct HasConstIterator : std::false_type {}; -template <typename T> +}; + +// HasConstIterator<T>::value is true iff there exists a type T::const_iterator. +template <typename T, typename = void> +struct HasConstIterator : std::false_type {}; +template <typename T> struct HasConstIterator<T, y_absl::void_t<typename T::const_iterator>> - : std::true_type {}; - + : std::true_type {}; + // HasEmplace<T>::value is true iff there exists a method T::emplace(). template <typename T, typename = void> struct HasEmplace : std::false_type {}; @@ -189,213 +189,213 @@ template <typename T> struct HasEmplace<T, y_absl::void_t<decltype(std::declval<T>().emplace())>> : std::true_type {}; -// IsInitializerList<T>::value is true iff T is an std::initializer_list. More -// details below in Splitter<> where this is used. -std::false_type IsInitializerListDispatch(...); // default: No -template <typename T> -std::true_type IsInitializerListDispatch(std::initializer_list<T>*); -template <typename T> -struct IsInitializerList - : decltype(IsInitializerListDispatch(static_cast<T*>(nullptr))) {}; - -// A SplitterIsConvertibleTo<C>::type alias exists iff the specified condition -// is true for type 'C'. -// -// Restricts conversion to container-like types (by testing for the presence of -// a const_iterator member type) and also to disable conversion to an -// std::initializer_list (which also has a const_iterator). Otherwise, code -// compiled in C++11 will get an error due to ambiguous conversion paths (in -// C++11 std::vector<T>::operator= is overloaded to take either a std::vector<T> -// or an std::initializer_list<T>). - -template <typename C, bool has_value_type, bool has_mapped_type> -struct SplitterIsConvertibleToImpl : std::false_type {}; - -template <typename C> -struct SplitterIsConvertibleToImpl<C, true, false> +// IsInitializerList<T>::value is true iff T is an std::initializer_list. More +// details below in Splitter<> where this is used. +std::false_type IsInitializerListDispatch(...); // default: No +template <typename T> +std::true_type IsInitializerListDispatch(std::initializer_list<T>*); +template <typename T> +struct IsInitializerList + : decltype(IsInitializerListDispatch(static_cast<T*>(nullptr))) {}; + +// A SplitterIsConvertibleTo<C>::type alias exists iff the specified condition +// is true for type 'C'. +// +// Restricts conversion to container-like types (by testing for the presence of +// a const_iterator member type) and also to disable conversion to an +// std::initializer_list (which also has a const_iterator). Otherwise, code +// compiled in C++11 will get an error due to ambiguous conversion paths (in +// C++11 std::vector<T>::operator= is overloaded to take either a std::vector<T> +// or an std::initializer_list<T>). + +template <typename C, bool has_value_type, bool has_mapped_type> +struct SplitterIsConvertibleToImpl : std::false_type {}; + +template <typename C> +struct SplitterIsConvertibleToImpl<C, true, false> : std::is_constructible<typename C::value_type, y_absl::string_view> {}; - -template <typename C> -struct SplitterIsConvertibleToImpl<C, true, true> + +template <typename C> +struct SplitterIsConvertibleToImpl<C, true, true> : y_absl::conjunction< std::is_constructible<typename C::key_type, y_absl::string_view>, std::is_constructible<typename C::mapped_type, y_absl::string_view>> {}; - -template <typename C> -struct SplitterIsConvertibleTo - : SplitterIsConvertibleToImpl< - C, -#ifdef _GLIBCXX_DEBUG - !IsStrictlyBaseOfAndConvertibleToSTLContainer<C>::value && -#endif // _GLIBCXX_DEBUG - !IsInitializerList< - typename std::remove_reference<C>::type>::value && - HasValueType<C>::value && HasConstIterator<C>::value, - HasMappedType<C>::value> { -}; - + +template <typename C> +struct SplitterIsConvertibleTo + : SplitterIsConvertibleToImpl< + C, +#ifdef _GLIBCXX_DEBUG + !IsStrictlyBaseOfAndConvertibleToSTLContainer<C>::value && +#endif // _GLIBCXX_DEBUG + !IsInitializerList< + typename std::remove_reference<C>::type>::value && + HasValueType<C>::value && HasConstIterator<C>::value, + HasMappedType<C>::value> { +}; + // This class implements the range that is returned by y_absl::StrSplit(). This -// class has templated conversion operators that allow it to be implicitly -// converted to a variety of types that the caller may have specified on the -// left-hand side of an assignment. -// -// The main interface for interacting with this class is through its implicit -// conversion operators. However, this class may also be used like a container -// in that it has .begin() and .end() member functions. It may also be used -// within a range-for loop. -// -// Output containers can be collections of any type that is constructible from +// class has templated conversion operators that allow it to be implicitly +// converted to a variety of types that the caller may have specified on the +// left-hand side of an assignment. +// +// The main interface for interacting with this class is through its implicit +// conversion operators. However, this class may also be used like a container +// in that it has .begin() and .end() member functions. It may also be used +// within a range-for loop. +// +// Output containers can be collections of any type that is constructible from // an y_absl::string_view. -// -// An Predicate functor may be supplied. This predicate will be used to filter -// the split strings: only strings for which the predicate returns true will be +// +// An Predicate functor may be supplied. This predicate will be used to filter +// the split strings: only strings for which the predicate returns true will be // kept. A Predicate object is any unary functor that takes an y_absl::string_view -// and returns bool. +// and returns bool. // // The StringType parameter can be either string_view or string, depending on // whether the Splitter refers to a string stored elsewhere, or if the string // resides inside the Splitter itself. template <typename Delimiter, typename Predicate, typename StringType> -class Splitter { - public: - using DelimiterType = Delimiter; - using PredicateType = Predicate; - using const_iterator = strings_internal::SplitIterator<Splitter>; - using value_type = typename std::iterator_traits<const_iterator>::value_type; - +class Splitter { + public: + using DelimiterType = Delimiter; + using PredicateType = Predicate; + using const_iterator = strings_internal::SplitIterator<Splitter>; + using value_type = typename std::iterator_traits<const_iterator>::value_type; + Splitter(StringType input_text, Delimiter d, Predicate p) - : text_(std::move(input_text)), - delimiter_(std::move(d)), - predicate_(std::move(p)) {} - + : text_(std::move(input_text)), + delimiter_(std::move(d)), + predicate_(std::move(p)) {} + y_absl::string_view text() const { return text_; } - const Delimiter& delimiter() const { return delimiter_; } - const Predicate& predicate() const { return predicate_; } - + const Delimiter& delimiter() const { return delimiter_; } + const Predicate& predicate() const { return predicate_; } + // Range functions that iterate the split substrings as y_absl::string_view - // objects. These methods enable a Splitter to be used in a range-based for - // loop. - const_iterator begin() const { return {const_iterator::kInitState, this}; } - const_iterator end() const { return {const_iterator::kEndState, this}; } - - // An implicit conversion operator that is restricted to only those containers - // that the splitter is convertible to. - template <typename Container, - typename = typename std::enable_if< - SplitterIsConvertibleTo<Container>::value>::type> - operator Container() const { // NOLINT(runtime/explicit) - return ConvertToContainer<Container, typename Container::value_type, - HasMappedType<Container>::value>()(*this); - } - - // Returns a pair with its .first and .second members set to the first two - // strings returned by the begin() iterator. Either/both of .first and .second - // will be constructed with empty strings if the iterator doesn't have a - // corresponding value. - template <typename First, typename Second> - operator std::pair<First, Second>() const { // NOLINT(runtime/explicit) + // objects. These methods enable a Splitter to be used in a range-based for + // loop. + const_iterator begin() const { return {const_iterator::kInitState, this}; } + const_iterator end() const { return {const_iterator::kEndState, this}; } + + // An implicit conversion operator that is restricted to only those containers + // that the splitter is convertible to. + template <typename Container, + typename = typename std::enable_if< + SplitterIsConvertibleTo<Container>::value>::type> + operator Container() const { // NOLINT(runtime/explicit) + return ConvertToContainer<Container, typename Container::value_type, + HasMappedType<Container>::value>()(*this); + } + + // Returns a pair with its .first and .second members set to the first two + // strings returned by the begin() iterator. Either/both of .first and .second + // will be constructed with empty strings if the iterator doesn't have a + // corresponding value. + template <typename First, typename Second> + operator std::pair<First, Second>() const { // NOLINT(runtime/explicit) y_absl::string_view first, second; - auto it = begin(); - if (it != end()) { - first = *it; - if (++it != end()) { - second = *it; - } - } - return {First(first), Second(second)}; - } - - private: - // ConvertToContainer is a functor converting a Splitter to the requested - // Container of ValueType. It is specialized below to optimize splitting to - // certain combinations of Container and ValueType. - // - // This base template handles the generic case of storing the split results in - // the requested non-map-like container and converting the split substrings to - // the requested type. - template <typename Container, typename ValueType, bool is_map = false> - struct ConvertToContainer { - Container operator()(const Splitter& splitter) const { - Container c; - auto it = std::inserter(c, c.end()); + auto it = begin(); + if (it != end()) { + first = *it; + if (++it != end()) { + second = *it; + } + } + return {First(first), Second(second)}; + } + + private: + // ConvertToContainer is a functor converting a Splitter to the requested + // Container of ValueType. It is specialized below to optimize splitting to + // certain combinations of Container and ValueType. + // + // This base template handles the generic case of storing the split results in + // the requested non-map-like container and converting the split substrings to + // the requested type. + template <typename Container, typename ValueType, bool is_map = false> + struct ConvertToContainer { + Container operator()(const Splitter& splitter) const { + Container c; + auto it = std::inserter(c, c.end()); for (const auto& sp : splitter) { - *it++ = ValueType(sp); - } - return c; - } - }; - + *it++ = ValueType(sp); + } + return c; + } + }; + // Partial specialization for a std::vector<y_absl::string_view>. - // - // Optimized for the common case of splitting to a + // + // Optimized for the common case of splitting to a // std::vector<y_absl::string_view>. In this case we first split the results to // a small array of y_absl::string_view on the stack, to reduce reallocations. - template <typename A> + template <typename A> struct ConvertToContainer<std::vector<y_absl::string_view, A>, y_absl::string_view, false> { std::vector<y_absl::string_view, A> operator()( - const Splitter& splitter) const { - struct raw_view { - const char* data; - size_t size; + const Splitter& splitter) const { + struct raw_view { + const char* data; + size_t size; operator y_absl::string_view() const { // NOLINT(runtime/explicit) - return {data, size}; - } - }; + return {data, size}; + } + }; std::vector<y_absl::string_view, A> v; - std::array<raw_view, 16> ar; - for (auto it = splitter.begin(); !it.at_end();) { - size_t index = 0; - do { - ar[index].data = it->data(); - ar[index].size = it->size(); - ++it; - } while (++index != ar.size() && !it.at_end()); - v.insert(v.end(), ar.begin(), ar.begin() + index); - } - return v; - } - }; - + std::array<raw_view, 16> ar; + for (auto it = splitter.begin(); !it.at_end();) { + size_t index = 0; + do { + ar[index].data = it->data(); + ar[index].size = it->size(); + ++it; + } while (++index != ar.size() && !it.at_end()); + v.insert(v.end(), ar.begin(), ar.begin() + index); + } + return v; + } + }; + // Partial specialization for a std::vector<TString>. - // + // // Optimized for the common case of splitting to a std::vector<TString>. // In this case we first split the results to a std::vector<y_absl::string_view> // so the returned std::vector<TString> can have space reserved to avoid // TString moves. - template <typename A> + template <typename A> struct ConvertToContainer<std::vector<TString, A>, TString, false> { std::vector<TString, A> operator()(const Splitter& splitter) const { const std::vector<y_absl::string_view> v = splitter; return std::vector<TString, A>(v.begin(), v.end()); - } - }; - - // Partial specialization for containers of pairs (e.g., maps). - // - // The algorithm is to insert a new pair into the map for each even-numbered - // item, with the even-numbered item as the key with a default-constructed - // value. Each odd-numbered item will then be assigned to the last pair's - // value. - template <typename Container, typename First, typename Second> - struct ConvertToContainer<Container, std::pair<const First, Second>, true> { + } + }; + + // Partial specialization for containers of pairs (e.g., maps). + // + // The algorithm is to insert a new pair into the map for each even-numbered + // item, with the even-numbered item as the key with a default-constructed + // value. Each odd-numbered item will then be assigned to the last pair's + // value. + template <typename Container, typename First, typename Second> + struct ConvertToContainer<Container, std::pair<const First, Second>, true> { using iterator = typename Container::iterator; - Container operator()(const Splitter& splitter) const { - Container m; + Container operator()(const Splitter& splitter) const { + Container m; iterator it; - bool insert = true; + bool insert = true; for (const y_absl::string_view sv : splitter) { - if (insert) { + if (insert) { it = InsertOrEmplace(&m, sv); - } else { + } else { it->second = Second(sv); - } - insert = !insert; - } - return m; - } - + } + insert = !insert; + } + return m; + } + // Inserts the key and an empty value into the map, returning an iterator to // the inserted item. We use emplace() if available, otherwise insert(). template <typename M> @@ -411,20 +411,20 @@ class Splitter { M* m, y_absl::string_view key) { return ToIter(m->insert(std::make_pair(First(key), Second("")))); } - + static iterator ToIter(std::pair<iterator, bool> pair) { return pair.first; } static iterator ToIter(iterator iter) { return iter; } - }; - + }; + StringType text_; - Delimiter delimiter_; - Predicate predicate_; -}; - -} // namespace strings_internal + Delimiter delimiter_; + Predicate predicate_; +}; + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ + +#endif // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/utf8.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/utf8.cc index 06b1cae79d..0d7d12b86f 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/utf8.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/utf8.cc @@ -1,53 +1,53 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// UTF8 utilities, implemented to reduce dependencies. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// UTF8 utilities, implemented to reduce dependencies. + #include "y_absl/strings/internal/utf8.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) { - if (utf8_char <= 0x7F) { - *buffer = static_cast<char>(utf8_char); - return 1; - } else if (utf8_char <= 0x7FF) { - buffer[1] = 0x80 | (utf8_char & 0x3F); - utf8_char >>= 6; - buffer[0] = 0xC0 | utf8_char; - return 2; - } else if (utf8_char <= 0xFFFF) { - buffer[2] = 0x80 | (utf8_char & 0x3F); - utf8_char >>= 6; - buffer[1] = 0x80 | (utf8_char & 0x3F); - utf8_char >>= 6; - buffer[0] = 0xE0 | utf8_char; - return 3; - } else { - buffer[3] = 0x80 | (utf8_char & 0x3F); - utf8_char >>= 6; - buffer[2] = 0x80 | (utf8_char & 0x3F); - utf8_char >>= 6; - buffer[1] = 0x80 | (utf8_char & 0x3F); - utf8_char >>= 6; - buffer[0] = 0xF0 | utf8_char; - return 4; - } -} - -} // namespace strings_internal +namespace strings_internal { + +size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) { + if (utf8_char <= 0x7F) { + *buffer = static_cast<char>(utf8_char); + return 1; + } else if (utf8_char <= 0x7FF) { + buffer[1] = 0x80 | (utf8_char & 0x3F); + utf8_char >>= 6; + buffer[0] = 0xC0 | utf8_char; + return 2; + } else if (utf8_char <= 0xFFFF) { + buffer[2] = 0x80 | (utf8_char & 0x3F); + utf8_char >>= 6; + buffer[1] = 0x80 | (utf8_char & 0x3F); + utf8_char >>= 6; + buffer[0] = 0xE0 | utf8_char; + return 3; + } else { + buffer[3] = 0x80 | (utf8_char & 0x3F); + utf8_char >>= 6; + buffer[2] = 0x80 | (utf8_char & 0x3F); + utf8_char >>= 6; + buffer[1] = 0x80 | (utf8_char & 0x3F); + utf8_char >>= 6; + buffer[0] = 0xF0 | utf8_char; + return 4; + } +} + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/utf8.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/utf8.h index 1b2d6abd51..d237336c84 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/utf8.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/utf8.h @@ -1,50 +1,50 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// UTF8 utilities, implemented to reduce dependencies. - -#ifndef ABSL_STRINGS_INTERNAL_UTF8_H_ -#define ABSL_STRINGS_INTERNAL_UTF8_H_ - -#include <cstddef> -#include <cstdint> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// UTF8 utilities, implemented to reduce dependencies. + +#ifndef ABSL_STRINGS_INTERNAL_UTF8_H_ +#define ABSL_STRINGS_INTERNAL_UTF8_H_ + +#include <cstddef> +#include <cstdint> + #include "y_absl/base/config.h" namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -// For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes -// out the UTF-8 encoding into buffer, and returns the number of chars -// it wrote. -// -// As described in https://tools.ietf.org/html/rfc3629#section-3 , the encodings -// are: -// 00 - 7F : 0xxxxxxx -// 80 - 7FF : 110xxxxx 10xxxxxx -// 800 - FFFF : 1110xxxx 10xxxxxx 10xxxxxx -// 10000 - 10FFFF : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -// -// Values greater than 0x10FFFF are not supported and may or may not write -// characters into buffer, however never will more than kMaxEncodedUTF8Size -// bytes be written, regardless of the value of utf8_char. -enum { kMaxEncodedUTF8Size = 4 }; -size_t EncodeUTF8Char(char *buffer, char32_t utf8_char); - -} // namespace strings_internal +namespace strings_internal { + +// For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes +// out the UTF-8 encoding into buffer, and returns the number of chars +// it wrote. +// +// As described in https://tools.ietf.org/html/rfc3629#section-3 , the encodings +// are: +// 00 - 7F : 0xxxxxxx +// 80 - 7FF : 110xxxxx 10xxxxxx +// 800 - FFFF : 1110xxxx 10xxxxxx 10xxxxxx +// 10000 - 10FFFF : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +// +// Values greater than 0x10FFFF are not supported and may or may not write +// characters into buffer, however never will more than kMaxEncodedUTF8Size +// bytes be written, regardless of the value of utf8_char. +enum { kMaxEncodedUTF8Size = 4 }; +size_t EncodeUTF8Char(char *buffer, char32_t utf8_char); + +} // namespace strings_internal ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_UTF8_H_ + +#endif // ABSL_STRINGS_INTERNAL_UTF8_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.cc index 3197bdf432..d66931c18f 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.cc @@ -1,43 +1,43 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/match.h" - + #include "y_absl/strings/internal/memutil.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - + bool EqualsIgnoreCase(y_absl::string_view piece1, y_absl::string_view piece2) noexcept { - return (piece1.size() == piece2.size() && + return (piece1.size() == piece2.size() && 0 == y_absl::strings_internal::memcasecmp(piece1.data(), piece2.data(), - piece1.size())); + piece1.size())); // memcasecmp uses y_absl::ascii_tolower(). -} - +} + bool StartsWithIgnoreCase(y_absl::string_view text, y_absl::string_view prefix) noexcept { - return (text.size() >= prefix.size()) && - EqualsIgnoreCase(text.substr(0, prefix.size()), prefix); -} - + return (text.size() >= prefix.size()) && + EqualsIgnoreCase(text.substr(0, prefix.size()), prefix); +} + bool EndsWithIgnoreCase(y_absl::string_view text, y_absl::string_view suffix) noexcept { - return (text.size() >= suffix.size()) && - EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix); -} - + return (text.size() >= suffix.size()) && + EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix); +} + ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.h index 4709abc93f..3f9fbf016e 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.h @@ -1,100 +1,100 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: match.h -// ----------------------------------------------------------------------------- -// -// This file contains simple utilities for performing string matching checks. +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: match.h +// ----------------------------------------------------------------------------- +// +// This file contains simple utilities for performing string matching checks. // All of these function parameters are specified as `y_absl::string_view`, // meaning that these functions can accept `TString`, `y_absl::string_view` or // NUL-terminated C-style strings. -// -// Examples: +// +// Examples: // TString s = "foo"; // y_absl::string_view sv = "f"; // assert(y_absl::StrContains(s, sv)); -// -// Note: The order of parameters in these functions is designed to mimic the -// order an equivalent member function would exhibit; +// +// Note: The order of parameters in these functions is designed to mimic the +// order an equivalent member function would exhibit; // e.g. `s.Contains(x)` ==> `y_absl::StrContains(s, x). -#ifndef ABSL_STRINGS_MATCH_H_ -#define ABSL_STRINGS_MATCH_H_ - -#include <cstring> - +#ifndef ABSL_STRINGS_MATCH_H_ +#define ABSL_STRINGS_MATCH_H_ + +#include <cstring> + #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -// StrContains() -// -// Returns whether a given string `haystack` contains the substring `needle`. + +// StrContains() +// +// Returns whether a given string `haystack` contains the substring `needle`. inline bool StrContains(y_absl::string_view haystack, y_absl::string_view needle) noexcept { - return haystack.find(needle, 0) != haystack.npos; -} - + return haystack.find(needle, 0) != haystack.npos; +} + inline bool StrContains(y_absl::string_view haystack, char needle) noexcept { return haystack.find(needle) != haystack.npos; } -// StartsWith() -// -// Returns whether a given string `text` begins with `prefix`. +// StartsWith() +// +// Returns whether a given string `text` begins with `prefix`. inline bool StartsWith(y_absl::string_view text, y_absl::string_view prefix) noexcept { - return prefix.empty() || - (text.size() >= prefix.size() && - memcmp(text.data(), prefix.data(), prefix.size()) == 0); -} - -// EndsWith() -// -// Returns whether a given string `text` ends with `suffix`. + return prefix.empty() || + (text.size() >= prefix.size() && + memcmp(text.data(), prefix.data(), prefix.size()) == 0); +} + +// EndsWith() +// +// Returns whether a given string `text` ends with `suffix`. inline bool EndsWith(y_absl::string_view text, y_absl::string_view suffix) noexcept { - return suffix.empty() || - (text.size() >= suffix.size() && - memcmp(text.data() + (text.size() - suffix.size()), suffix.data(), - suffix.size()) == 0); -} - -// EqualsIgnoreCase() -// -// Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring -// case in the comparison. + return suffix.empty() || + (text.size() >= suffix.size() && + memcmp(text.data() + (text.size() - suffix.size()), suffix.data(), + suffix.size()) == 0); +} + +// EqualsIgnoreCase() +// +// Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring +// case in the comparison. bool EqualsIgnoreCase(y_absl::string_view piece1, y_absl::string_view piece2) noexcept; - -// StartsWithIgnoreCase() -// -// Returns whether a given ASCII string `text` starts with `prefix`, -// ignoring case in the comparison. + +// StartsWithIgnoreCase() +// +// Returns whether a given ASCII string `text` starts with `prefix`, +// ignoring case in the comparison. bool StartsWithIgnoreCase(y_absl::string_view text, y_absl::string_view prefix) noexcept; - -// EndsWithIgnoreCase() -// -// Returns whether a given ASCII string `text` ends with `suffix`, ignoring -// case in the comparison. + +// EndsWithIgnoreCase() +// +// Returns whether a given ASCII string `text` ends with `suffix`, ignoring +// case in the comparison. bool EndsWithIgnoreCase(y_absl::string_view text, y_absl::string_view suffix) noexcept; - + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_MATCH_H_ + +#endif // ABSL_STRINGS_MATCH_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.cc index 528d044fa6..965ce2e014 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.cc @@ -1,35 +1,35 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This file contains string processing functions related to -// numeric values. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file contains string processing functions related to +// numeric values. + #include "y_absl/strings/numbers.h" - -#include <algorithm> -#include <cassert> -#include <cfloat> // for DBL_DIG and FLT_DIG -#include <cmath> // for HUGE_VAL -#include <cstdint> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <iterator> -#include <limits> -#include <memory> -#include <utility> - + +#include <algorithm> +#include <cassert> +#include <cfloat> // for DBL_DIG and FLT_DIG +#include <cmath> // for HUGE_VAL +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <iterator> +#include <limits> +#include <memory> +#include <utility> + #include "y_absl/base/attributes.h" #include "y_absl/base/internal/raw_logging.h" #include "y_absl/numeric/bits.h" @@ -39,713 +39,713 @@ #include "y_absl/strings/internal/memutil.h" #include "y_absl/strings/match.h" #include "y_absl/strings/str_cat.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - + bool SimpleAtof(y_absl::string_view str, float* out) { - *out = 0.0; - str = StripAsciiWhitespace(str); + *out = 0.0; + str = StripAsciiWhitespace(str); // std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one // is present, skip it, while avoiding accepting "+-0" as valid. - if (!str.empty() && str[0] == '+') { - str.remove_prefix(1); + if (!str.empty() && str[0] == '+') { + str.remove_prefix(1); if (!str.empty() && str[0] == '-') { return false; } - } + } auto result = y_absl::from_chars(str.data(), str.data() + str.size(), *out); - if (result.ec == std::errc::invalid_argument) { - return false; - } - if (result.ptr != str.data() + str.size()) { - // not all non-whitespace characters consumed - return false; - } - // from_chars() with DR 3081's current wording will return max() on - // overflow. SimpleAtof returns infinity instead. - if (result.ec == std::errc::result_out_of_range) { - if (*out > 1.0) { - *out = std::numeric_limits<float>::infinity(); - } else if (*out < -1.0) { - *out = -std::numeric_limits<float>::infinity(); - } - } - return true; -} - + if (result.ec == std::errc::invalid_argument) { + return false; + } + if (result.ptr != str.data() + str.size()) { + // not all non-whitespace characters consumed + return false; + } + // from_chars() with DR 3081's current wording will return max() on + // overflow. SimpleAtof returns infinity instead. + if (result.ec == std::errc::result_out_of_range) { + if (*out > 1.0) { + *out = std::numeric_limits<float>::infinity(); + } else if (*out < -1.0) { + *out = -std::numeric_limits<float>::infinity(); + } + } + return true; +} + bool SimpleAtod(y_absl::string_view str, double* out) { - *out = 0.0; - str = StripAsciiWhitespace(str); + *out = 0.0; + str = StripAsciiWhitespace(str); // std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one // is present, skip it, while avoiding accepting "+-0" as valid. - if (!str.empty() && str[0] == '+') { - str.remove_prefix(1); + if (!str.empty() && str[0] == '+') { + str.remove_prefix(1); if (!str.empty() && str[0] == '-') { return false; } - } + } auto result = y_absl::from_chars(str.data(), str.data() + str.size(), *out); - if (result.ec == std::errc::invalid_argument) { - return false; - } - if (result.ptr != str.data() + str.size()) { - // not all non-whitespace characters consumed - return false; - } - // from_chars() with DR 3081's current wording will return max() on - // overflow. SimpleAtod returns infinity instead. - if (result.ec == std::errc::result_out_of_range) { - if (*out > 1.0) { - *out = std::numeric_limits<double>::infinity(); - } else if (*out < -1.0) { - *out = -std::numeric_limits<double>::infinity(); - } - } - return true; -} - + if (result.ec == std::errc::invalid_argument) { + return false; + } + if (result.ptr != str.data() + str.size()) { + // not all non-whitespace characters consumed + return false; + } + // from_chars() with DR 3081's current wording will return max() on + // overflow. SimpleAtod returns infinity instead. + if (result.ec == std::errc::result_out_of_range) { + if (*out > 1.0) { + *out = std::numeric_limits<double>::infinity(); + } else if (*out < -1.0) { + *out = -std::numeric_limits<double>::infinity(); + } + } + return true; +} + bool SimpleAtob(y_absl::string_view str, bool* out) { - ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr."); - if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") || - EqualsIgnoreCase(str, "yes") || EqualsIgnoreCase(str, "y") || - EqualsIgnoreCase(str, "1")) { - *out = true; - return true; - } - if (EqualsIgnoreCase(str, "false") || EqualsIgnoreCase(str, "f") || - EqualsIgnoreCase(str, "no") || EqualsIgnoreCase(str, "n") || - EqualsIgnoreCase(str, "0")) { - *out = false; - return true; - } - return false; -} - -// ---------------------------------------------------------------------- -// FastIntToBuffer() overloads -// -// Like the Fast*ToBuffer() functions above, these are intended for speed. -// Unlike the Fast*ToBuffer() functions, however, these functions write -// their output to the beginning of the buffer. The caller is responsible -// for ensuring that the buffer has enough space to hold the output. -// -// Returns a pointer to the end of the string (i.e. the null character -// terminating the string). -// ---------------------------------------------------------------------- - -namespace { - -// Used to optimize printing a decimal number's final digit. -const char one_ASCII_final_digits[10][2] { - {'0', 0}, {'1', 0}, {'2', 0}, {'3', 0}, {'4', 0}, - {'5', 0}, {'6', 0}, {'7', 0}, {'8', 0}, {'9', 0}, -}; - -} // namespace - -char* numbers_internal::FastIntToBuffer(uint32_t i, char* buffer) { - uint32_t digits; - // The idea of this implementation is to trim the number of divides to as few - // as possible, and also reducing memory stores and branches, by going in - // steps of two digits at a time rather than one whenever possible. - // The huge-number case is first, in the hopes that the compiler will output - // that case in one branch-free block of code, and only output conditional - // branches into it from below. - if (i >= 1000000000) { // >= 1,000,000,000 - digits = i / 100000000; // 100,000,000 - i -= digits * 100000000; - PutTwoDigits(digits, buffer); - buffer += 2; - lt100_000_000: - digits = i / 1000000; // 1,000,000 - i -= digits * 1000000; - PutTwoDigits(digits, buffer); - buffer += 2; - lt1_000_000: - digits = i / 10000; // 10,000 - i -= digits * 10000; - PutTwoDigits(digits, buffer); - buffer += 2; - lt10_000: - digits = i / 100; - i -= digits * 100; - PutTwoDigits(digits, buffer); - buffer += 2; - lt100: - digits = i; - PutTwoDigits(digits, buffer); - buffer += 2; - *buffer = 0; - return buffer; - } - - if (i < 100) { - digits = i; - if (i >= 10) goto lt100; - memcpy(buffer, one_ASCII_final_digits[i], 2); - return buffer + 1; - } - if (i < 10000) { // 10,000 - if (i >= 1000) goto lt10_000; - digits = i / 100; - i -= digits * 100; - *buffer++ = '0' + digits; - goto lt100; - } - if (i < 1000000) { // 1,000,000 - if (i >= 100000) goto lt1_000_000; - digits = i / 10000; // 10,000 - i -= digits * 10000; - *buffer++ = '0' + digits; - goto lt10_000; - } - if (i < 100000000) { // 100,000,000 - if (i >= 10000000) goto lt100_000_000; - digits = i / 1000000; // 1,000,000 - i -= digits * 1000000; - *buffer++ = '0' + digits; - goto lt1_000_000; - } - // we already know that i < 1,000,000,000 - digits = i / 100000000; // 100,000,000 - i -= digits * 100000000; - *buffer++ = '0' + digits; - goto lt100_000_000; -} - -char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) { - uint32_t u = i; - if (i < 0) { - *buffer++ = '-'; - // We need to do the negation in modular (i.e., "unsigned") - // arithmetic; MSVC++ apprently warns for plain "-u", so - // we write the equivalent expression "0 - u" instead. - u = 0 - u; - } - return numbers_internal::FastIntToBuffer(u, buffer); -} - -char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { - uint32_t u32 = static_cast<uint32_t>(i); - if (u32 == i) return numbers_internal::FastIntToBuffer(u32, buffer); - - // Here we know i has at least 10 decimal digits. - uint64_t top_1to11 = i / 1000000000; - u32 = static_cast<uint32_t>(i - top_1to11 * 1000000000); - uint32_t top_1to11_32 = static_cast<uint32_t>(top_1to11); - - if (top_1to11_32 == top_1to11) { - buffer = numbers_internal::FastIntToBuffer(top_1to11_32, buffer); - } else { - // top_1to11 has more than 32 bits too; print it in two steps. - uint32_t top_8to9 = static_cast<uint32_t>(top_1to11 / 100); - uint32_t mid_2 = static_cast<uint32_t>(top_1to11 - top_8to9 * 100); - buffer = numbers_internal::FastIntToBuffer(top_8to9, buffer); - PutTwoDigits(mid_2, buffer); - buffer += 2; - } - - // We have only 9 digits now, again the maximum uint32_t can handle fully. - uint32_t digits = u32 / 10000000; // 10,000,000 - u32 -= digits * 10000000; - PutTwoDigits(digits, buffer); - buffer += 2; - digits = u32 / 100000; // 100,000 - u32 -= digits * 100000; - PutTwoDigits(digits, buffer); - buffer += 2; - digits = u32 / 1000; // 1,000 - u32 -= digits * 1000; - PutTwoDigits(digits, buffer); - buffer += 2; - digits = u32 / 10; - u32 -= digits * 10; - PutTwoDigits(digits, buffer); - buffer += 2; - memcpy(buffer, one_ASCII_final_digits[u32], 2); - return buffer + 1; -} - -char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) { - uint64_t u = i; - if (i < 0) { - *buffer++ = '-'; - u = 0 - u; - } - return numbers_internal::FastIntToBuffer(u, buffer); -} - -// Given a 128-bit number expressed as a pair of uint64_t, high half first, -// return that number multiplied by the given 32-bit value. If the result is -// too large to fit in a 128-bit number, divide it by 2 until it fits. -static std::pair<uint64_t, uint64_t> Mul32(std::pair<uint64_t, uint64_t> num, - uint32_t mul) { - uint64_t bits0_31 = num.second & 0xFFFFFFFF; - uint64_t bits32_63 = num.second >> 32; - uint64_t bits64_95 = num.first & 0xFFFFFFFF; - uint64_t bits96_127 = num.first >> 32; - - // The picture so far: each of these 64-bit values has only the lower 32 bits - // filled in. - // bits96_127: [ 00000000 xxxxxxxx ] - // bits64_95: [ 00000000 xxxxxxxx ] - // bits32_63: [ 00000000 xxxxxxxx ] - // bits0_31: [ 00000000 xxxxxxxx ] - - bits0_31 *= mul; - bits32_63 *= mul; - bits64_95 *= mul; - bits96_127 *= mul; - - // Now the top halves may also have value, though all 64 of their bits will - // never be set at the same time, since they are a result of a 32x32 bit - // multiply. This makes the carry calculation slightly easier. - // bits96_127: [ mmmmmmmm | mmmmmmmm ] - // bits64_95: [ | mmmmmmmm mmmmmmmm | ] - // bits32_63: | [ mmmmmmmm | mmmmmmmm ] - // bits0_31: | [ | mmmmmmmm mmmmmmmm ] - // eventually: [ bits128_up | ...bits64_127.... | ..bits0_63... ] - - uint64_t bits0_63 = bits0_31 + (bits32_63 << 32); - uint64_t bits64_127 = bits64_95 + (bits96_127 << 32) + (bits32_63 >> 32) + - (bits0_63 < bits0_31); - uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95); - if (bits128_up == 0) return {bits64_127, bits0_63}; - + ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr."); + if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") || + EqualsIgnoreCase(str, "yes") || EqualsIgnoreCase(str, "y") || + EqualsIgnoreCase(str, "1")) { + *out = true; + return true; + } + if (EqualsIgnoreCase(str, "false") || EqualsIgnoreCase(str, "f") || + EqualsIgnoreCase(str, "no") || EqualsIgnoreCase(str, "n") || + EqualsIgnoreCase(str, "0")) { + *out = false; + return true; + } + return false; +} + +// ---------------------------------------------------------------------- +// FastIntToBuffer() overloads +// +// Like the Fast*ToBuffer() functions above, these are intended for speed. +// Unlike the Fast*ToBuffer() functions, however, these functions write +// their output to the beginning of the buffer. The caller is responsible +// for ensuring that the buffer has enough space to hold the output. +// +// Returns a pointer to the end of the string (i.e. the null character +// terminating the string). +// ---------------------------------------------------------------------- + +namespace { + +// Used to optimize printing a decimal number's final digit. +const char one_ASCII_final_digits[10][2] { + {'0', 0}, {'1', 0}, {'2', 0}, {'3', 0}, {'4', 0}, + {'5', 0}, {'6', 0}, {'7', 0}, {'8', 0}, {'9', 0}, +}; + +} // namespace + +char* numbers_internal::FastIntToBuffer(uint32_t i, char* buffer) { + uint32_t digits; + // The idea of this implementation is to trim the number of divides to as few + // as possible, and also reducing memory stores and branches, by going in + // steps of two digits at a time rather than one whenever possible. + // The huge-number case is first, in the hopes that the compiler will output + // that case in one branch-free block of code, and only output conditional + // branches into it from below. + if (i >= 1000000000) { // >= 1,000,000,000 + digits = i / 100000000; // 100,000,000 + i -= digits * 100000000; + PutTwoDigits(digits, buffer); + buffer += 2; + lt100_000_000: + digits = i / 1000000; // 1,000,000 + i -= digits * 1000000; + PutTwoDigits(digits, buffer); + buffer += 2; + lt1_000_000: + digits = i / 10000; // 10,000 + i -= digits * 10000; + PutTwoDigits(digits, buffer); + buffer += 2; + lt10_000: + digits = i / 100; + i -= digits * 100; + PutTwoDigits(digits, buffer); + buffer += 2; + lt100: + digits = i; + PutTwoDigits(digits, buffer); + buffer += 2; + *buffer = 0; + return buffer; + } + + if (i < 100) { + digits = i; + if (i >= 10) goto lt100; + memcpy(buffer, one_ASCII_final_digits[i], 2); + return buffer + 1; + } + if (i < 10000) { // 10,000 + if (i >= 1000) goto lt10_000; + digits = i / 100; + i -= digits * 100; + *buffer++ = '0' + digits; + goto lt100; + } + if (i < 1000000) { // 1,000,000 + if (i >= 100000) goto lt1_000_000; + digits = i / 10000; // 10,000 + i -= digits * 10000; + *buffer++ = '0' + digits; + goto lt10_000; + } + if (i < 100000000) { // 100,000,000 + if (i >= 10000000) goto lt100_000_000; + digits = i / 1000000; // 1,000,000 + i -= digits * 1000000; + *buffer++ = '0' + digits; + goto lt1_000_000; + } + // we already know that i < 1,000,000,000 + digits = i / 100000000; // 100,000,000 + i -= digits * 100000000; + *buffer++ = '0' + digits; + goto lt100_000_000; +} + +char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) { + uint32_t u = i; + if (i < 0) { + *buffer++ = '-'; + // We need to do the negation in modular (i.e., "unsigned") + // arithmetic; MSVC++ apprently warns for plain "-u", so + // we write the equivalent expression "0 - u" instead. + u = 0 - u; + } + return numbers_internal::FastIntToBuffer(u, buffer); +} + +char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { + uint32_t u32 = static_cast<uint32_t>(i); + if (u32 == i) return numbers_internal::FastIntToBuffer(u32, buffer); + + // Here we know i has at least 10 decimal digits. + uint64_t top_1to11 = i / 1000000000; + u32 = static_cast<uint32_t>(i - top_1to11 * 1000000000); + uint32_t top_1to11_32 = static_cast<uint32_t>(top_1to11); + + if (top_1to11_32 == top_1to11) { + buffer = numbers_internal::FastIntToBuffer(top_1to11_32, buffer); + } else { + // top_1to11 has more than 32 bits too; print it in two steps. + uint32_t top_8to9 = static_cast<uint32_t>(top_1to11 / 100); + uint32_t mid_2 = static_cast<uint32_t>(top_1to11 - top_8to9 * 100); + buffer = numbers_internal::FastIntToBuffer(top_8to9, buffer); + PutTwoDigits(mid_2, buffer); + buffer += 2; + } + + // We have only 9 digits now, again the maximum uint32_t can handle fully. + uint32_t digits = u32 / 10000000; // 10,000,000 + u32 -= digits * 10000000; + PutTwoDigits(digits, buffer); + buffer += 2; + digits = u32 / 100000; // 100,000 + u32 -= digits * 100000; + PutTwoDigits(digits, buffer); + buffer += 2; + digits = u32 / 1000; // 1,000 + u32 -= digits * 1000; + PutTwoDigits(digits, buffer); + buffer += 2; + digits = u32 / 10; + u32 -= digits * 10; + PutTwoDigits(digits, buffer); + buffer += 2; + memcpy(buffer, one_ASCII_final_digits[u32], 2); + return buffer + 1; +} + +char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) { + uint64_t u = i; + if (i < 0) { + *buffer++ = '-'; + u = 0 - u; + } + return numbers_internal::FastIntToBuffer(u, buffer); +} + +// Given a 128-bit number expressed as a pair of uint64_t, high half first, +// return that number multiplied by the given 32-bit value. If the result is +// too large to fit in a 128-bit number, divide it by 2 until it fits. +static std::pair<uint64_t, uint64_t> Mul32(std::pair<uint64_t, uint64_t> num, + uint32_t mul) { + uint64_t bits0_31 = num.second & 0xFFFFFFFF; + uint64_t bits32_63 = num.second >> 32; + uint64_t bits64_95 = num.first & 0xFFFFFFFF; + uint64_t bits96_127 = num.first >> 32; + + // The picture so far: each of these 64-bit values has only the lower 32 bits + // filled in. + // bits96_127: [ 00000000 xxxxxxxx ] + // bits64_95: [ 00000000 xxxxxxxx ] + // bits32_63: [ 00000000 xxxxxxxx ] + // bits0_31: [ 00000000 xxxxxxxx ] + + bits0_31 *= mul; + bits32_63 *= mul; + bits64_95 *= mul; + bits96_127 *= mul; + + // Now the top halves may also have value, though all 64 of their bits will + // never be set at the same time, since they are a result of a 32x32 bit + // multiply. This makes the carry calculation slightly easier. + // bits96_127: [ mmmmmmmm | mmmmmmmm ] + // bits64_95: [ | mmmmmmmm mmmmmmmm | ] + // bits32_63: | [ mmmmmmmm | mmmmmmmm ] + // bits0_31: | [ | mmmmmmmm mmmmmmmm ] + // eventually: [ bits128_up | ...bits64_127.... | ..bits0_63... ] + + uint64_t bits0_63 = bits0_31 + (bits32_63 << 32); + uint64_t bits64_127 = bits64_95 + (bits96_127 << 32) + (bits32_63 >> 32) + + (bits0_63 < bits0_31); + uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95); + if (bits128_up == 0) return {bits64_127, bits0_63}; + auto shift = static_cast<unsigned>(bit_width(bits128_up)); - uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift)); - uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift)); - return {hi, lo}; -} - -// Compute num * 5 ^ expfive, and return the first 128 bits of the result, -// where the first bit is always a one. So PowFive(1, 0) starts 0b100000, -// PowFive(1, 1) starts 0b101000, PowFive(1, 2) starts 0b110010, etc. -static std::pair<uint64_t, uint64_t> PowFive(uint64_t num, int expfive) { - std::pair<uint64_t, uint64_t> result = {num, 0}; - while (expfive >= 13) { - // 5^13 is the highest power of five that will fit in a 32-bit integer. - result = Mul32(result, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5); - expfive -= 13; - } - constexpr int powers_of_five[13] = { - 1, - 5, - 5 * 5, - 5 * 5 * 5, - 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5}; - result = Mul32(result, powers_of_five[expfive & 15]); + uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift)); + uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift)); + return {hi, lo}; +} + +// Compute num * 5 ^ expfive, and return the first 128 bits of the result, +// where the first bit is always a one. So PowFive(1, 0) starts 0b100000, +// PowFive(1, 1) starts 0b101000, PowFive(1, 2) starts 0b110010, etc. +static std::pair<uint64_t, uint64_t> PowFive(uint64_t num, int expfive) { + std::pair<uint64_t, uint64_t> result = {num, 0}; + while (expfive >= 13) { + // 5^13 is the highest power of five that will fit in a 32-bit integer. + result = Mul32(result, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5); + expfive -= 13; + } + constexpr int powers_of_five[13] = { + 1, + 5, + 5 * 5, + 5 * 5 * 5, + 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5}; + result = Mul32(result, powers_of_five[expfive & 15]); int shift = countl_zero(result.first); - if (shift != 0) { - result.first = (result.first << shift) + (result.second >> (64 - shift)); - result.second = (result.second << shift); - } - return result; -} - -struct ExpDigits { - int32_t exponent; - char digits[6]; -}; - -// SplitToSix converts value, a positive double-precision floating-point number, -// into a base-10 exponent and 6 ASCII digits, where the first digit is never -// zero. For example, SplitToSix(1) returns an exponent of zero and a digits -// array of {'1', '0', '0', '0', '0', '0'}. If value is exactly halfway between -// two possible representations, e.g. value = 100000.5, then "round to even" is -// performed. -static ExpDigits SplitToSix(const double value) { - ExpDigits exp_dig; - int exp = 5; - double d = value; - // First step: calculate a close approximation of the output, where the - // value d will be between 100,000 and 999,999, representing the digits - // in the output ASCII array, and exp is the base-10 exponent. It would be - // faster to use a table here, and to look up the base-2 exponent of value, - // however value is an IEEE-754 64-bit number, so the table would have 2,000 - // entries, which is not cache-friendly. - if (d >= 999999.5) { - if (d >= 1e+261) exp += 256, d *= 1e-256; - if (d >= 1e+133) exp += 128, d *= 1e-128; - if (d >= 1e+69) exp += 64, d *= 1e-64; - if (d >= 1e+37) exp += 32, d *= 1e-32; - if (d >= 1e+21) exp += 16, d *= 1e-16; - if (d >= 1e+13) exp += 8, d *= 1e-8; - if (d >= 1e+9) exp += 4, d *= 1e-4; - if (d >= 1e+7) exp += 2, d *= 1e-2; - if (d >= 1e+6) exp += 1, d *= 1e-1; - } else { - if (d < 1e-250) exp -= 256, d *= 1e256; - if (d < 1e-122) exp -= 128, d *= 1e128; - if (d < 1e-58) exp -= 64, d *= 1e64; - if (d < 1e-26) exp -= 32, d *= 1e32; - if (d < 1e-10) exp -= 16, d *= 1e16; - if (d < 1e-2) exp -= 8, d *= 1e8; - if (d < 1e+2) exp -= 4, d *= 1e4; - if (d < 1e+4) exp -= 2, d *= 1e2; - if (d < 1e+5) exp -= 1, d *= 1e1; - } - // At this point, d is in the range [99999.5..999999.5) and exp is in the - // range [-324..308]. Since we need to round d up, we want to add a half - // and truncate. - // However, the technique above may have lost some precision, due to its - // repeated multiplication by constants that each may be off by half a bit - // of precision. This only matters if we're close to the edge though. - // Since we'd like to know if the fractional part of d is close to a half, - // we multiply it by 65536 and see if the fractional part is close to 32768. - // (The number doesn't have to be a power of two,but powers of two are faster) - uint64_t d64k = d * 65536; - int dddddd; // A 6-digit decimal integer. - if ((d64k % 65536) == 32767 || (d64k % 65536) == 32768) { - // OK, it's fairly likely that precision was lost above, which is - // not a surprise given only 52 mantissa bits are available. Therefore - // redo the calculation using 128-bit numbers. (64 bits are not enough). - - // Start out with digits rounded down; maybe add one below. - dddddd = static_cast<int>(d64k / 65536); - - // mantissa is a 64-bit integer representing M.mmm... * 2^63. The actual - // value we're representing, of course, is M.mmm... * 2^exp2. - int exp2; - double m = std::frexp(value, &exp2); - uint64_t mantissa = m * (32768.0 * 65536.0 * 65536.0 * 65536.0); - // std::frexp returns an m value in the range [0.5, 1.0), however we - // can't multiply it by 2^64 and convert to an integer because some FPUs - // throw an exception when converting an number higher than 2^63 into an - // integer - even an unsigned 64-bit integer! Fortunately it doesn't matter - // since m only has 52 significant bits anyway. - mantissa <<= 1; - exp2 -= 64; // not needed, but nice for debugging - - // OK, we are here to compare: - // (dddddd + 0.5) * 10^(exp-5) vs. mantissa * 2^exp2 - // so we can round up dddddd if appropriate. Those values span the full - // range of 600 orders of magnitude of IEE 64-bit floating-point. - // Fortunately, we already know they are very close, so we don't need to - // track the base-2 exponent of both sides. This greatly simplifies the - // the math since the 2^exp2 calculation is unnecessary and the power-of-10 - // calculation can become a power-of-5 instead. - - std::pair<uint64_t, uint64_t> edge, val; - if (exp >= 6) { - // Compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa - // Since we're tossing powers of two, 2 * dddddd + 1 is the - // same as dddddd + 0.5 - edge = PowFive(2 * dddddd + 1, exp - 5); - - val.first = mantissa; - val.second = 0; - } else { - // We can't compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa as we did - // above because (exp - 5) is negative. So we compare (dddddd + 0.5) to - // mantissa * 5 ^ (5 - exp) - edge = PowFive(2 * dddddd + 1, 0); - - val = PowFive(mantissa, 5 - exp); - } - // printf("exp=%d %016lx %016lx vs %016lx %016lx\n", exp, val.first, - // val.second, edge.first, edge.second); - if (val > edge) { - dddddd++; - } else if (val == edge) { - dddddd += (dddddd & 1); - } - } else { - // Here, we are not close to the edge. - dddddd = static_cast<int>((d64k + 32768) / 65536); - } - if (dddddd == 1000000) { - dddddd = 100000; - exp += 1; - } - exp_dig.exponent = exp; - - int two_digits = dddddd / 10000; - dddddd -= two_digits * 10000; - numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[0]); - - two_digits = dddddd / 100; - dddddd -= two_digits * 100; - numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[2]); - - numbers_internal::PutTwoDigits(dddddd, &exp_dig.digits[4]); - return exp_dig; -} - -// Helper function for fast formatting of floating-point. -// The result is the same as "%g", a.k.a. "%.6g". -size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) { - static_assert(std::numeric_limits<float>::is_iec559, - "IEEE-754/IEC-559 support only"); - - char* out = buffer; // we write data to out, incrementing as we go, but - // FloatToBuffer always returns the address of the buffer - // passed in. - - if (std::isnan(d)) { - strcpy(out, "nan"); // NOLINT(runtime/printf) - return 3; - } - if (d == 0) { // +0 and -0 are handled here - if (std::signbit(d)) *out++ = '-'; - *out++ = '0'; - *out = 0; - return out - buffer; - } - if (d < 0) { - *out++ = '-'; - d = -d; - } + if (shift != 0) { + result.first = (result.first << shift) + (result.second >> (64 - shift)); + result.second = (result.second << shift); + } + return result; +} + +struct ExpDigits { + int32_t exponent; + char digits[6]; +}; + +// SplitToSix converts value, a positive double-precision floating-point number, +// into a base-10 exponent and 6 ASCII digits, where the first digit is never +// zero. For example, SplitToSix(1) returns an exponent of zero and a digits +// array of {'1', '0', '0', '0', '0', '0'}. If value is exactly halfway between +// two possible representations, e.g. value = 100000.5, then "round to even" is +// performed. +static ExpDigits SplitToSix(const double value) { + ExpDigits exp_dig; + int exp = 5; + double d = value; + // First step: calculate a close approximation of the output, where the + // value d will be between 100,000 and 999,999, representing the digits + // in the output ASCII array, and exp is the base-10 exponent. It would be + // faster to use a table here, and to look up the base-2 exponent of value, + // however value is an IEEE-754 64-bit number, so the table would have 2,000 + // entries, which is not cache-friendly. + if (d >= 999999.5) { + if (d >= 1e+261) exp += 256, d *= 1e-256; + if (d >= 1e+133) exp += 128, d *= 1e-128; + if (d >= 1e+69) exp += 64, d *= 1e-64; + if (d >= 1e+37) exp += 32, d *= 1e-32; + if (d >= 1e+21) exp += 16, d *= 1e-16; + if (d >= 1e+13) exp += 8, d *= 1e-8; + if (d >= 1e+9) exp += 4, d *= 1e-4; + if (d >= 1e+7) exp += 2, d *= 1e-2; + if (d >= 1e+6) exp += 1, d *= 1e-1; + } else { + if (d < 1e-250) exp -= 256, d *= 1e256; + if (d < 1e-122) exp -= 128, d *= 1e128; + if (d < 1e-58) exp -= 64, d *= 1e64; + if (d < 1e-26) exp -= 32, d *= 1e32; + if (d < 1e-10) exp -= 16, d *= 1e16; + if (d < 1e-2) exp -= 8, d *= 1e8; + if (d < 1e+2) exp -= 4, d *= 1e4; + if (d < 1e+4) exp -= 2, d *= 1e2; + if (d < 1e+5) exp -= 1, d *= 1e1; + } + // At this point, d is in the range [99999.5..999999.5) and exp is in the + // range [-324..308]. Since we need to round d up, we want to add a half + // and truncate. + // However, the technique above may have lost some precision, due to its + // repeated multiplication by constants that each may be off by half a bit + // of precision. This only matters if we're close to the edge though. + // Since we'd like to know if the fractional part of d is close to a half, + // we multiply it by 65536 and see if the fractional part is close to 32768. + // (The number doesn't have to be a power of two,but powers of two are faster) + uint64_t d64k = d * 65536; + int dddddd; // A 6-digit decimal integer. + if ((d64k % 65536) == 32767 || (d64k % 65536) == 32768) { + // OK, it's fairly likely that precision was lost above, which is + // not a surprise given only 52 mantissa bits are available. Therefore + // redo the calculation using 128-bit numbers. (64 bits are not enough). + + // Start out with digits rounded down; maybe add one below. + dddddd = static_cast<int>(d64k / 65536); + + // mantissa is a 64-bit integer representing M.mmm... * 2^63. The actual + // value we're representing, of course, is M.mmm... * 2^exp2. + int exp2; + double m = std::frexp(value, &exp2); + uint64_t mantissa = m * (32768.0 * 65536.0 * 65536.0 * 65536.0); + // std::frexp returns an m value in the range [0.5, 1.0), however we + // can't multiply it by 2^64 and convert to an integer because some FPUs + // throw an exception when converting an number higher than 2^63 into an + // integer - even an unsigned 64-bit integer! Fortunately it doesn't matter + // since m only has 52 significant bits anyway. + mantissa <<= 1; + exp2 -= 64; // not needed, but nice for debugging + + // OK, we are here to compare: + // (dddddd + 0.5) * 10^(exp-5) vs. mantissa * 2^exp2 + // so we can round up dddddd if appropriate. Those values span the full + // range of 600 orders of magnitude of IEE 64-bit floating-point. + // Fortunately, we already know they are very close, so we don't need to + // track the base-2 exponent of both sides. This greatly simplifies the + // the math since the 2^exp2 calculation is unnecessary and the power-of-10 + // calculation can become a power-of-5 instead. + + std::pair<uint64_t, uint64_t> edge, val; + if (exp >= 6) { + // Compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa + // Since we're tossing powers of two, 2 * dddddd + 1 is the + // same as dddddd + 0.5 + edge = PowFive(2 * dddddd + 1, exp - 5); + + val.first = mantissa; + val.second = 0; + } else { + // We can't compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa as we did + // above because (exp - 5) is negative. So we compare (dddddd + 0.5) to + // mantissa * 5 ^ (5 - exp) + edge = PowFive(2 * dddddd + 1, 0); + + val = PowFive(mantissa, 5 - exp); + } + // printf("exp=%d %016lx %016lx vs %016lx %016lx\n", exp, val.first, + // val.second, edge.first, edge.second); + if (val > edge) { + dddddd++; + } else if (val == edge) { + dddddd += (dddddd & 1); + } + } else { + // Here, we are not close to the edge. + dddddd = static_cast<int>((d64k + 32768) / 65536); + } + if (dddddd == 1000000) { + dddddd = 100000; + exp += 1; + } + exp_dig.exponent = exp; + + int two_digits = dddddd / 10000; + dddddd -= two_digits * 10000; + numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[0]); + + two_digits = dddddd / 100; + dddddd -= two_digits * 100; + numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[2]); + + numbers_internal::PutTwoDigits(dddddd, &exp_dig.digits[4]); + return exp_dig; +} + +// Helper function for fast formatting of floating-point. +// The result is the same as "%g", a.k.a. "%.6g". +size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) { + static_assert(std::numeric_limits<float>::is_iec559, + "IEEE-754/IEC-559 support only"); + + char* out = buffer; // we write data to out, incrementing as we go, but + // FloatToBuffer always returns the address of the buffer + // passed in. + + if (std::isnan(d)) { + strcpy(out, "nan"); // NOLINT(runtime/printf) + return 3; + } + if (d == 0) { // +0 and -0 are handled here + if (std::signbit(d)) *out++ = '-'; + *out++ = '0'; + *out = 0; + return out - buffer; + } + if (d < 0) { + *out++ = '-'; + d = -d; + } if (d > std::numeric_limits<double>::max()) { - strcpy(out, "inf"); // NOLINT(runtime/printf) - return out + 3 - buffer; - } - - auto exp_dig = SplitToSix(d); - int exp = exp_dig.exponent; - const char* digits = exp_dig.digits; - out[0] = '0'; - out[1] = '.'; - switch (exp) { - case 5: - memcpy(out, &digits[0], 6), out += 6; - *out = 0; - return out - buffer; - case 4: - memcpy(out, &digits[0], 5), out += 5; - if (digits[5] != '0') { - *out++ = '.'; - *out++ = digits[5]; - } - *out = 0; - return out - buffer; - case 3: - memcpy(out, &digits[0], 4), out += 4; - if ((digits[5] | digits[4]) != '0') { - *out++ = '.'; - *out++ = digits[4]; - if (digits[5] != '0') *out++ = digits[5]; - } - *out = 0; - return out - buffer; - case 2: - memcpy(out, &digits[0], 3), out += 3; - *out++ = '.'; - memcpy(out, &digits[3], 3); - out += 3; - while (out[-1] == '0') --out; - if (out[-1] == '.') --out; - *out = 0; - return out - buffer; - case 1: - memcpy(out, &digits[0], 2), out += 2; - *out++ = '.'; - memcpy(out, &digits[2], 4); - out += 4; - while (out[-1] == '0') --out; - if (out[-1] == '.') --out; - *out = 0; - return out - buffer; - case 0: - memcpy(out, &digits[0], 1), out += 1; - *out++ = '.'; - memcpy(out, &digits[1], 5); - out += 5; - while (out[-1] == '0') --out; - if (out[-1] == '.') --out; - *out = 0; - return out - buffer; - case -4: - out[2] = '0'; - ++out; - ABSL_FALLTHROUGH_INTENDED; - case -3: - out[2] = '0'; - ++out; - ABSL_FALLTHROUGH_INTENDED; - case -2: - out[2] = '0'; - ++out; - ABSL_FALLTHROUGH_INTENDED; - case -1: - out += 2; - memcpy(out, &digits[0], 6); - out += 6; - while (out[-1] == '0') --out; - *out = 0; - return out - buffer; - } - assert(exp < -4 || exp >= 6); - out[0] = digits[0]; - assert(out[1] == '.'); - out += 2; - memcpy(out, &digits[1], 5), out += 5; - while (out[-1] == '0') --out; - if (out[-1] == '.') --out; - *out++ = 'e'; - if (exp > 0) { - *out++ = '+'; - } else { - *out++ = '-'; - exp = -exp; - } - if (exp > 99) { - int dig1 = exp / 100; - exp -= dig1 * 100; - *out++ = '0' + dig1; - } - PutTwoDigits(exp, out); - out += 2; - *out = 0; - return out - buffer; -} - -namespace { -// Represents integer values of digits. -// Uses 36 to indicate an invalid character since we support -// bases up to 36. -static const int8_t kAsciiToInt[256] = { - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, // 16 36s. - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 36, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36}; - -// Parse the sign and optional hex or oct prefix in text. + strcpy(out, "inf"); // NOLINT(runtime/printf) + return out + 3 - buffer; + } + + auto exp_dig = SplitToSix(d); + int exp = exp_dig.exponent; + const char* digits = exp_dig.digits; + out[0] = '0'; + out[1] = '.'; + switch (exp) { + case 5: + memcpy(out, &digits[0], 6), out += 6; + *out = 0; + return out - buffer; + case 4: + memcpy(out, &digits[0], 5), out += 5; + if (digits[5] != '0') { + *out++ = '.'; + *out++ = digits[5]; + } + *out = 0; + return out - buffer; + case 3: + memcpy(out, &digits[0], 4), out += 4; + if ((digits[5] | digits[4]) != '0') { + *out++ = '.'; + *out++ = digits[4]; + if (digits[5] != '0') *out++ = digits[5]; + } + *out = 0; + return out - buffer; + case 2: + memcpy(out, &digits[0], 3), out += 3; + *out++ = '.'; + memcpy(out, &digits[3], 3); + out += 3; + while (out[-1] == '0') --out; + if (out[-1] == '.') --out; + *out = 0; + return out - buffer; + case 1: + memcpy(out, &digits[0], 2), out += 2; + *out++ = '.'; + memcpy(out, &digits[2], 4); + out += 4; + while (out[-1] == '0') --out; + if (out[-1] == '.') --out; + *out = 0; + return out - buffer; + case 0: + memcpy(out, &digits[0], 1), out += 1; + *out++ = '.'; + memcpy(out, &digits[1], 5); + out += 5; + while (out[-1] == '0') --out; + if (out[-1] == '.') --out; + *out = 0; + return out - buffer; + case -4: + out[2] = '0'; + ++out; + ABSL_FALLTHROUGH_INTENDED; + case -3: + out[2] = '0'; + ++out; + ABSL_FALLTHROUGH_INTENDED; + case -2: + out[2] = '0'; + ++out; + ABSL_FALLTHROUGH_INTENDED; + case -1: + out += 2; + memcpy(out, &digits[0], 6); + out += 6; + while (out[-1] == '0') --out; + *out = 0; + return out - buffer; + } + assert(exp < -4 || exp >= 6); + out[0] = digits[0]; + assert(out[1] == '.'); + out += 2; + memcpy(out, &digits[1], 5), out += 5; + while (out[-1] == '0') --out; + if (out[-1] == '.') --out; + *out++ = 'e'; + if (exp > 0) { + *out++ = '+'; + } else { + *out++ = '-'; + exp = -exp; + } + if (exp > 99) { + int dig1 = exp / 100; + exp -= dig1 * 100; + *out++ = '0' + dig1; + } + PutTwoDigits(exp, out); + out += 2; + *out = 0; + return out - buffer; +} + +namespace { +// Represents integer values of digits. +// Uses 36 to indicate an invalid character since we support +// bases up to 36. +static const int8_t kAsciiToInt[256] = { + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, // 16 36s. + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 36, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36}; + +// Parse the sign and optional hex or oct prefix in text. inline bool safe_parse_sign_and_base(y_absl::string_view* text /*inout*/, - int* base_ptr /*inout*/, - bool* negative_ptr /*output*/) { - if (text->data() == nullptr) { - return false; - } - - const char* start = text->data(); - const char* end = start + text->size(); - int base = *base_ptr; - - // Consume whitespace. + int* base_ptr /*inout*/, + bool* negative_ptr /*output*/) { + if (text->data() == nullptr) { + return false; + } + + const char* start = text->data(); + const char* end = start + text->size(); + int base = *base_ptr; + + // Consume whitespace. while (start < end && y_absl::ascii_isspace(start[0])) { - ++start; - } + ++start; + } while (start < end && y_absl::ascii_isspace(end[-1])) { - --end; - } - if (start >= end) { - return false; - } - - // Consume sign. - *negative_ptr = (start[0] == '-'); - if (*negative_ptr || start[0] == '+') { - ++start; - if (start >= end) { - return false; - } - } - - // Consume base-dependent prefix. - // base 0: "0x" -> base 16, "0" -> base 8, default -> base 10 - // base 16: "0x" -> base 16 - // Also validate the base. - if (base == 0) { - if (end - start >= 2 && start[0] == '0' && - (start[1] == 'x' || start[1] == 'X')) { - base = 16; - start += 2; - if (start >= end) { - // "0x" with no digits after is invalid. - return false; - } - } else if (end - start >= 1 && start[0] == '0') { - base = 8; - start += 1; - } else { - base = 10; - } - } else if (base == 16) { - if (end - start >= 2 && start[0] == '0' && - (start[1] == 'x' || start[1] == 'X')) { - start += 2; - if (start >= end) { - // "0x" with no digits after is invalid. - return false; - } - } - } else if (base >= 2 && base <= 36) { - // okay - } else { - return false; - } + --end; + } + if (start >= end) { + return false; + } + + // Consume sign. + *negative_ptr = (start[0] == '-'); + if (*negative_ptr || start[0] == '+') { + ++start; + if (start >= end) { + return false; + } + } + + // Consume base-dependent prefix. + // base 0: "0x" -> base 16, "0" -> base 8, default -> base 10 + // base 16: "0x" -> base 16 + // Also validate the base. + if (base == 0) { + if (end - start >= 2 && start[0] == '0' && + (start[1] == 'x' || start[1] == 'X')) { + base = 16; + start += 2; + if (start >= end) { + // "0x" with no digits after is invalid. + return false; + } + } else if (end - start >= 1 && start[0] == '0') { + base = 8; + start += 1; + } else { + base = 10; + } + } else if (base == 16) { + if (end - start >= 2 && start[0] == '0' && + (start[1] == 'x' || start[1] == 'X')) { + start += 2; + if (start >= end) { + // "0x" with no digits after is invalid. + return false; + } + } + } else if (base >= 2 && base <= 36) { + // okay + } else { + return false; + } *text = y_absl::string_view(start, end - start); - *base_ptr = base; - return true; -} - -// Consume digits. -// -// The classic loop: -// -// for each digit -// value = value * base + digit -// value *= sign -// -// The classic loop needs overflow checking. It also fails on the most -// negative integer, -2147483648 in 32-bit two's complement representation. -// -// My improved loop: -// -// if (!negative) -// for each digit -// value = value * base -// value = value + digit -// else -// for each digit -// value = value * base -// value = value - digit -// -// Overflow checking becomes simple. - -// Lookup tables per IntType: -// vmax/base and vmin/base are precomputed because division costs at least 8ns. -// TODO(junyer): Doing this per base instead (i.e. an array of structs, not a -// struct of arrays) would probably be better in terms of d-cache for the most -// commonly used bases. -template <typename IntType> -struct LookupTables { + *base_ptr = base; + return true; +} + +// Consume digits. +// +// The classic loop: +// +// for each digit +// value = value * base + digit +// value *= sign +// +// The classic loop needs overflow checking. It also fails on the most +// negative integer, -2147483648 in 32-bit two's complement representation. +// +// My improved loop: +// +// if (!negative) +// for each digit +// value = value * base +// value = value + digit +// else +// for each digit +// value = value * base +// value = value - digit +// +// Overflow checking becomes simple. + +// Lookup tables per IntType: +// vmax/base and vmin/base are precomputed because division costs at least 8ns. +// TODO(junyer): Doing this per base instead (i.e. an array of structs, not a +// struct of arrays) would probably be better in terms of d-cache for the most +// commonly used bases. +template <typename IntType> +struct LookupTables { ABSL_CONST_INIT static const IntType kVmaxOverBase[]; ABSL_CONST_INIT static const IntType kVminOverBase[]; -}; - -// An array initializer macro for X/base where base in [0, 36]. -// However, note that lookups for base in [0, 1] should never happen because -// base has been validated to be in [2, 36] by safe_parse_sign_and_base(). -#define X_OVER_BASE_INITIALIZER(X) \ - { \ - 0, 0, X / 2, X / 3, X / 4, X / 5, X / 6, X / 7, X / 8, X / 9, X / 10, \ - X / 11, X / 12, X / 13, X / 14, X / 15, X / 16, X / 17, X / 18, \ - X / 19, X / 20, X / 21, X / 22, X / 23, X / 24, X / 25, X / 26, \ - X / 27, X / 28, X / 29, X / 30, X / 31, X / 32, X / 33, X / 34, \ - X / 35, X / 36, \ - } - +}; + +// An array initializer macro for X/base where base in [0, 36]. +// However, note that lookups for base in [0, 1] should never happen because +// base has been validated to be in [2, 36] by safe_parse_sign_and_base(). +#define X_OVER_BASE_INITIALIZER(X) \ + { \ + 0, 0, X / 2, X / 3, X / 4, X / 5, X / 6, X / 7, X / 8, X / 9, X / 10, \ + X / 11, X / 12, X / 13, X / 14, X / 15, X / 16, X / 17, X / 18, \ + X / 19, X / 20, X / 21, X / 22, X / 23, X / 24, X / 25, X / 26, \ + X / 27, X / 28, X / 29, X / 30, X / 31, X / 32, X / 33, X / 34, \ + X / 35, X / 36, \ + } + // This kVmaxOverBase is generated with // for (int base = 2; base < 37; ++base) { // y_absl::uint128 max = std::numeric_limits<y_absl::uint128>::max(); @@ -903,191 +903,191 @@ const int128 LookupTables<int128>::kVminOverBase[] = { MakeInt128(-256204778801521551, 14347467612885206813u), }; -template <typename IntType> -const IntType LookupTables<IntType>::kVmaxOverBase[] = - X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max()); - -template <typename IntType> -const IntType LookupTables<IntType>::kVminOverBase[] = - X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::min()); - -#undef X_OVER_BASE_INITIALIZER - -template <typename IntType> +template <typename IntType> +const IntType LookupTables<IntType>::kVmaxOverBase[] = + X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max()); + +template <typename IntType> +const IntType LookupTables<IntType>::kVminOverBase[] = + X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::min()); + +#undef X_OVER_BASE_INITIALIZER + +template <typename IntType> inline bool safe_parse_positive_int(y_absl::string_view text, int base, - IntType* value_p) { - IntType value = 0; - const IntType vmax = std::numeric_limits<IntType>::max(); - assert(vmax > 0); - assert(base >= 0); - assert(vmax >= static_cast<IntType>(base)); - const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base]; + IntType* value_p) { + IntType value = 0; + const IntType vmax = std::numeric_limits<IntType>::max(); + assert(vmax > 0); + assert(base >= 0); + assert(vmax >= static_cast<IntType>(base)); + const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base]; assert(base < 2 || std::numeric_limits<IntType>::max() / base == vmax_over_base); - const char* start = text.data(); - const char* end = start + text.size(); - // loop over digits - for (; start < end; ++start) { - unsigned char c = static_cast<unsigned char>(start[0]); - int digit = kAsciiToInt[c]; - if (digit >= base) { - *value_p = value; - return false; - } - if (value > vmax_over_base) { - *value_p = vmax; - return false; - } - value *= base; - if (value > vmax - digit) { - *value_p = vmax; - return false; - } - value += digit; - } - *value_p = value; - return true; -} - -template <typename IntType> + const char* start = text.data(); + const char* end = start + text.size(); + // loop over digits + for (; start < end; ++start) { + unsigned char c = static_cast<unsigned char>(start[0]); + int digit = kAsciiToInt[c]; + if (digit >= base) { + *value_p = value; + return false; + } + if (value > vmax_over_base) { + *value_p = vmax; + return false; + } + value *= base; + if (value > vmax - digit) { + *value_p = vmax; + return false; + } + value += digit; + } + *value_p = value; + return true; +} + +template <typename IntType> inline bool safe_parse_negative_int(y_absl::string_view text, int base, - IntType* value_p) { - IntType value = 0; - const IntType vmin = std::numeric_limits<IntType>::min(); - assert(vmin < 0); - assert(vmin <= 0 - base); - IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base]; + IntType* value_p) { + IntType value = 0; + const IntType vmin = std::numeric_limits<IntType>::min(); + assert(vmin < 0); + assert(vmin <= 0 - base); + IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base]; assert(base < 2 || std::numeric_limits<IntType>::min() / base == vmin_over_base); - // 2003 c++ standard [expr.mul] - // "... the sign of the remainder is implementation-defined." - // Although (vmin/base)*base + vmin%base is always vmin. - // 2011 c++ standard tightens the spec but we cannot rely on it. - // TODO(junyer): Handle this in the lookup table generation. - if (vmin % base > 0) { - vmin_over_base += 1; - } - const char* start = text.data(); - const char* end = start + text.size(); - // loop over digits - for (; start < end; ++start) { - unsigned char c = static_cast<unsigned char>(start[0]); - int digit = kAsciiToInt[c]; - if (digit >= base) { - *value_p = value; - return false; - } - if (value < vmin_over_base) { - *value_p = vmin; - return false; - } - value *= base; - if (value < vmin + digit) { - *value_p = vmin; - return false; - } - value -= digit; - } - *value_p = value; - return true; -} - -// Input format based on POSIX.1-2008 strtol -// http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html -template <typename IntType> + // 2003 c++ standard [expr.mul] + // "... the sign of the remainder is implementation-defined." + // Although (vmin/base)*base + vmin%base is always vmin. + // 2011 c++ standard tightens the spec but we cannot rely on it. + // TODO(junyer): Handle this in the lookup table generation. + if (vmin % base > 0) { + vmin_over_base += 1; + } + const char* start = text.data(); + const char* end = start + text.size(); + // loop over digits + for (; start < end; ++start) { + unsigned char c = static_cast<unsigned char>(start[0]); + int digit = kAsciiToInt[c]; + if (digit >= base) { + *value_p = value; + return false; + } + if (value < vmin_over_base) { + *value_p = vmin; + return false; + } + value *= base; + if (value < vmin + digit) { + *value_p = vmin; + return false; + } + value -= digit; + } + *value_p = value; + return true; +} + +// Input format based on POSIX.1-2008 strtol +// http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html +template <typename IntType> inline bool safe_int_internal(y_absl::string_view text, IntType* value_p, - int base) { - *value_p = 0; - bool negative; - if (!safe_parse_sign_and_base(&text, &base, &negative)) { - return false; - } - if (!negative) { - return safe_parse_positive_int(text, base, value_p); - } else { - return safe_parse_negative_int(text, base, value_p); - } -} - -template <typename IntType> + int base) { + *value_p = 0; + bool negative; + if (!safe_parse_sign_and_base(&text, &base, &negative)) { + return false; + } + if (!negative) { + return safe_parse_positive_int(text, base, value_p); + } else { + return safe_parse_negative_int(text, base, value_p); + } +} + +template <typename IntType> inline bool safe_uint_internal(y_absl::string_view text, IntType* value_p, - int base) { - *value_p = 0; - bool negative; - if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) { - return false; - } - return safe_parse_positive_int(text, base, value_p); -} -} // anonymous namespace - -namespace numbers_internal { - -// Digit conversion. + int base) { + *value_p = 0; + bool negative; + if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) { + return false; + } + return safe_parse_positive_int(text, base, value_p); +} +} // anonymous namespace + +namespace numbers_internal { + +// Digit conversion. ABSL_CONST_INIT ABSL_DLL const char kHexChar[] = "0123456789abcdef"; - + ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] = - "000102030405060708090a0b0c0d0e0f" - "101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f" - "303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f" - "505152535455565758595a5b5c5d5e5f" - "606162636465666768696a6b6c6d6e6f" - "707172737475767778797a7b7c7d7e7f" - "808182838485868788898a8b8c8d8e8f" - "909192939495969798999a9b9c9d9e9f" - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; - + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + ABSL_CONST_INIT ABSL_DLL const char two_ASCII_digits[100][2] = { - {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, - {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, - {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, - {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, - {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, - {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, - {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'}, - {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, - {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, - {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, - {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, - {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'}, - {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, - {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, - {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, - {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, - {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; - + {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, + {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, + {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, + {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, + {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, + {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, + {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'}, + {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, + {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, + {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, + {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, + {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'}, + {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, + {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, + {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, + {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, + {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; + bool safe_strto32_base(y_absl::string_view text, int32_t* value, int base) { - return safe_int_internal<int32_t>(text, value, base); -} - + return safe_int_internal<int32_t>(text, value, base); +} + bool safe_strto64_base(y_absl::string_view text, int64_t* value, int base) { - return safe_int_internal<int64_t>(text, value, base); -} - + return safe_int_internal<int64_t>(text, value, base); +} + bool safe_strto128_base(y_absl::string_view text, int128* value, int base) { return safe_int_internal<y_absl::int128>(text, value, base); } bool safe_strtou32_base(y_absl::string_view text, uint32_t* value, int base) { - return safe_uint_internal<uint32_t>(text, value, base); -} - + return safe_uint_internal<uint32_t>(text, value, base); +} + bool safe_strtou64_base(y_absl::string_view text, uint64_t* value, int base) { - return safe_uint_internal<uint64_t>(text, value, base); -} - + return safe_uint_internal<uint64_t>(text, value, base); +} + bool safe_strtou128_base(y_absl::string_view text, uint128* value, int base) { return safe_uint_internal<y_absl::uint128>(text, value, base); -} - -} // namespace numbers_internal +} + +} // namespace numbers_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.h index ce181d8eb1..a76108c698 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.h @@ -1,28 +1,28 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: numbers.h -// ----------------------------------------------------------------------------- -// -// This package contains functions for converting strings to numbers. For -// converting numbers to strings, use `StrCat()` or `StrAppend()` in str_cat.h, -// which automatically detect and convert most number values appropriately. - -#ifndef ABSL_STRINGS_NUMBERS_H_ -#define ABSL_STRINGS_NUMBERS_H_ - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: numbers.h +// ----------------------------------------------------------------------------- +// +// This package contains functions for converting strings to numbers. For +// converting numbers to strings, use `StrCat()` or `StrAppend()` in str_cat.h, +// which automatically detect and convert most number values appropriately. + +#ifndef ABSL_STRINGS_NUMBERS_H_ +#define ABSL_STRINGS_NUMBERS_H_ + #if defined(__SSE4_2__) && !defined(__CUDACC__) #define _Y__SSE4_2__ #endif @@ -31,79 +31,79 @@ #ifdef _MSC_VER #include <intrin.h> #else -#include <x86intrin.h> +#include <x86intrin.h> +#endif #endif -#endif - -#include <cstddef> -#include <cstdlib> -#include <cstring> -#include <ctime> -#include <limits> + +#include <cstddef> +#include <cstdlib> +#include <cstring> +#include <ctime> +#include <limits> #include <util/generic/string.h> -#include <type_traits> - +#include <type_traits> + #include "y_absl/base/config.h" #ifdef _Y__SSE4_2__ -// TODO(jorg): Remove this when we figure out the right way -// to swap bytes on SSE 4.2 that works with the compilers -// we claim to support. Also, add tests for the compiler -// that doesn't support the Intel _bswap64 intrinsic but -// does support all the SSE 4.2 intrinsics +// TODO(jorg): Remove this when we figure out the right way +// to swap bytes on SSE 4.2 that works with the compilers +// we claim to support. Also, add tests for the compiler +// that doesn't support the Intel _bswap64 intrinsic but +// does support all the SSE 4.2 intrinsics #include "y_absl/base/internal/endian.h" -#endif +#endif #include "y_absl/base/macros.h" #include "y_absl/base/port.h" #include "y_absl/numeric/bits.h" #include "y_absl/numeric/int128.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -// SimpleAtoi() -// + +// SimpleAtoi() +// // Converts the given string (optionally followed or preceded by ASCII // whitespace) into an integer value, returning `true` if successful. The string // must reflect a base-10 integer whose value falls within the range of the // integer type (optionally preceded by a `+` or `-`). If any errors are // encountered, this function returns `false`, leaving `out` in an unspecified // state. -template <typename int_type> +template <typename int_type> ABSL_MUST_USE_RESULT bool SimpleAtoi(y_absl::string_view str, int_type* out); - -// SimpleAtof() -// -// Converts the given string (optionally followed or preceded by ASCII + +// SimpleAtof() +// +// Converts the given string (optionally followed or preceded by ASCII // whitespace) into a float, which may be rounded on overflow or underflow, // returning `true` if successful. -// See https://en.cppreference.com/w/c/string/byte/strtof for details about the -// allowed formats for `str`, except SimpleAtof() is locale-independent and will -// always use the "C" locale. If any errors are encountered, this function -// returns `false`, leaving `out` in an unspecified state. +// See https://en.cppreference.com/w/c/string/byte/strtof for details about the +// allowed formats for `str`, except SimpleAtof() is locale-independent and will +// always use the "C" locale. If any errors are encountered, this function +// returns `false`, leaving `out` in an unspecified state. ABSL_MUST_USE_RESULT bool SimpleAtof(y_absl::string_view str, float* out); - -// SimpleAtod() -// -// Converts the given string (optionally followed or preceded by ASCII + +// SimpleAtod() +// +// Converts the given string (optionally followed or preceded by ASCII // whitespace) into a double, which may be rounded on overflow or underflow, // returning `true` if successful. -// See https://en.cppreference.com/w/c/string/byte/strtof for details about the -// allowed formats for `str`, except SimpleAtod is locale-independent and will -// always use the "C" locale. If any errors are encountered, this function -// returns `false`, leaving `out` in an unspecified state. +// See https://en.cppreference.com/w/c/string/byte/strtof for details about the +// allowed formats for `str`, except SimpleAtod is locale-independent and will +// always use the "C" locale. If any errors are encountered, this function +// returns `false`, leaving `out` in an unspecified state. ABSL_MUST_USE_RESULT bool SimpleAtod(y_absl::string_view str, double* out); - -// SimpleAtob() -// -// Converts the given string into a boolean, returning `true` if successful. -// The following case-insensitive strings are interpreted as boolean `true`: -// "true", "t", "yes", "y", "1". The following case-insensitive strings -// are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any -// errors are encountered, this function returns `false`, leaving `out` in an -// unspecified state. + +// SimpleAtob() +// +// Converts the given string into a boolean, returning `true` if successful. +// The following case-insensitive strings are interpreted as boolean `true`: +// "true", "t", "yes", "y", "1". The following case-insensitive strings +// are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any +// errors are encountered, this function returns `false`, leaving `out` in an +// unspecified state. ABSL_MUST_USE_RESULT bool SimpleAtob(y_absl::string_view str, bool* out); - + // SimpleHexAtoi() // // Converts a hexadecimal string (optionally followed or preceded by ASCII @@ -125,32 +125,32 @@ ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(y_absl::string_view str, ABSL_NAMESPACE_END } // namespace y_absl - -// End of public API. Implementation details follow. - + +// End of public API. Implementation details follow. + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace numbers_internal { - -// Digit conversion. +namespace numbers_internal { + +// Digit conversion. ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef ABSL_DLL extern const char kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... ABSL_DLL extern const char two_ASCII_digits[100][2]; // 00, 01, 02, 03... - -// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the -// range 0 <= i < 100, and buf must have space for two characters. Example: -// char buf[2]; -// PutTwoDigits(42, buf); -// // buf[0] == '4' -// // buf[1] == '2' -inline void PutTwoDigits(size_t i, char* buf) { - assert(i < 100); - memcpy(buf, two_ASCII_digits[i], 2); -} - -// safe_strto?() functions for implementing SimpleAtoi() + +// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the +// range 0 <= i < 100, and buf must have space for two characters. Example: +// char buf[2]; +// PutTwoDigits(42, buf); +// // buf[0] == '4' +// // buf[1] == '2' +inline void PutTwoDigits(size_t i, char* buf) { + assert(i < 100); + memcpy(buf, two_ASCII_digits[i], 2); +} + +// safe_strto?() functions for implementing SimpleAtoi() bool safe_strto32_base(y_absl::string_view text, int32_t* value, int base); bool safe_strto64_base(y_absl::string_view text, int64_t* value, int base); @@ -159,124 +159,124 @@ bool safe_strto128_base(y_absl::string_view text, y_absl::int128* value, bool safe_strtou32_base(y_absl::string_view text, uint32_t* value, int base); bool safe_strtou64_base(y_absl::string_view text, uint64_t* value, int base); bool safe_strtou128_base(y_absl::string_view text, y_absl::uint128* value, - int base); - -static const int kFastToBufferSize = 32; -static const int kSixDigitsToBufferSize = 16; - -// Helper function for fast formatting of floating-point values. -// The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six -// significant digits are returned, trailing zeros are removed, and numbers -// outside the range 0.0001-999999 are output using scientific notation -// (1.23456e+06). This routine is heavily optimized. -// Required buffer size is `kSixDigitsToBufferSize`. -size_t SixDigitsToBuffer(double d, char* buffer); - -// These functions are intended for speed. All functions take an output buffer -// as an argument and return a pointer to the last byte they wrote, which is the -// terminating '\0'. At most `kFastToBufferSize` bytes are written. -char* FastIntToBuffer(int32_t, char*); -char* FastIntToBuffer(uint32_t, char*); -char* FastIntToBuffer(int64_t, char*); -char* FastIntToBuffer(uint64_t, char*); - -// For enums and integer types that are not an exact match for the types above, -// use templates to call the appropriate one of the four overloads above. -template <typename int_type> -char* FastIntToBuffer(int_type i, char* buffer) { - static_assert(sizeof(i) <= 64 / 8, - "FastIntToBuffer works only with 64-bit-or-less integers."); - // TODO(jorg): This signed-ness check is used because it works correctly - // with enums, and it also serves to check that int_type is not a pointer. - // If one day something like std::is_signed<enum E> works, switch to it. - if (static_cast<int_type>(1) - 2 < 0) { // Signed - if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit - return FastIntToBuffer(static_cast<int64_t>(i), buffer); - } else { // 32-bit or less - return FastIntToBuffer(static_cast<int32_t>(i), buffer); - } - } else { // Unsigned - if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit - return FastIntToBuffer(static_cast<uint64_t>(i), buffer); - } else { // 32-bit or less - return FastIntToBuffer(static_cast<uint32_t>(i), buffer); - } - } -} - -// Implementation of SimpleAtoi, generalized to support arbitrary base (used -// with base different from 10 elsewhere in Abseil implementation). -template <typename int_type> + int base); + +static const int kFastToBufferSize = 32; +static const int kSixDigitsToBufferSize = 16; + +// Helper function for fast formatting of floating-point values. +// The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six +// significant digits are returned, trailing zeros are removed, and numbers +// outside the range 0.0001-999999 are output using scientific notation +// (1.23456e+06). This routine is heavily optimized. +// Required buffer size is `kSixDigitsToBufferSize`. +size_t SixDigitsToBuffer(double d, char* buffer); + +// These functions are intended for speed. All functions take an output buffer +// as an argument and return a pointer to the last byte they wrote, which is the +// terminating '\0'. At most `kFastToBufferSize` bytes are written. +char* FastIntToBuffer(int32_t, char*); +char* FastIntToBuffer(uint32_t, char*); +char* FastIntToBuffer(int64_t, char*); +char* FastIntToBuffer(uint64_t, char*); + +// For enums and integer types that are not an exact match for the types above, +// use templates to call the appropriate one of the four overloads above. +template <typename int_type> +char* FastIntToBuffer(int_type i, char* buffer) { + static_assert(sizeof(i) <= 64 / 8, + "FastIntToBuffer works only with 64-bit-or-less integers."); + // TODO(jorg): This signed-ness check is used because it works correctly + // with enums, and it also serves to check that int_type is not a pointer. + // If one day something like std::is_signed<enum E> works, switch to it. + if (static_cast<int_type>(1) - 2 < 0) { // Signed + if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit + return FastIntToBuffer(static_cast<int64_t>(i), buffer); + } else { // 32-bit or less + return FastIntToBuffer(static_cast<int32_t>(i), buffer); + } + } else { // Unsigned + if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit + return FastIntToBuffer(static_cast<uint64_t>(i), buffer); + } else { // 32-bit or less + return FastIntToBuffer(static_cast<uint32_t>(i), buffer); + } + } +} + +// Implementation of SimpleAtoi, generalized to support arbitrary base (used +// with base different from 10 elsewhere in Abseil implementation). +template <typename int_type> ABSL_MUST_USE_RESULT bool safe_strtoi_base(y_absl::string_view s, int_type* out, - int base) { - static_assert(sizeof(*out) == 4 || sizeof(*out) == 8, - "SimpleAtoi works only with 32-bit or 64-bit integers."); - static_assert(!std::is_floating_point<int_type>::value, - "Use SimpleAtof or SimpleAtod instead."); - bool parsed; - // TODO(jorg): This signed-ness check is used because it works correctly - // with enums, and it also serves to check that int_type is not a pointer. - // If one day something like std::is_signed<enum E> works, switch to it. - if (static_cast<int_type>(1) - 2 < 0) { // Signed - if (sizeof(*out) == 64 / 8) { // 64-bit - int64_t val; - parsed = numbers_internal::safe_strto64_base(s, &val, base); - *out = static_cast<int_type>(val); - } else { // 32-bit - int32_t val; - parsed = numbers_internal::safe_strto32_base(s, &val, base); - *out = static_cast<int_type>(val); - } - } else { // Unsigned - if (sizeof(*out) == 64 / 8) { // 64-bit - uint64_t val; - parsed = numbers_internal::safe_strtou64_base(s, &val, base); - *out = static_cast<int_type>(val); - } else { // 32-bit - uint32_t val; - parsed = numbers_internal::safe_strtou32_base(s, &val, base); - *out = static_cast<int_type>(val); - } - } - return parsed; -} - -// FastHexToBufferZeroPad16() -// -// Outputs `val` into `out` as if by `snprintf(out, 17, "%016x", val)` but -// without the terminating null character. Thus `out` must be of length >= 16. -// Returns the number of non-pad digits of the output (it can never be zero -// since 0 has one digit). -inline size_t FastHexToBufferZeroPad16(uint64_t val, char* out) { + int base) { + static_assert(sizeof(*out) == 4 || sizeof(*out) == 8, + "SimpleAtoi works only with 32-bit or 64-bit integers."); + static_assert(!std::is_floating_point<int_type>::value, + "Use SimpleAtof or SimpleAtod instead."); + bool parsed; + // TODO(jorg): This signed-ness check is used because it works correctly + // with enums, and it also serves to check that int_type is not a pointer. + // If one day something like std::is_signed<enum E> works, switch to it. + if (static_cast<int_type>(1) - 2 < 0) { // Signed + if (sizeof(*out) == 64 / 8) { // 64-bit + int64_t val; + parsed = numbers_internal::safe_strto64_base(s, &val, base); + *out = static_cast<int_type>(val); + } else { // 32-bit + int32_t val; + parsed = numbers_internal::safe_strto32_base(s, &val, base); + *out = static_cast<int_type>(val); + } + } else { // Unsigned + if (sizeof(*out) == 64 / 8) { // 64-bit + uint64_t val; + parsed = numbers_internal::safe_strtou64_base(s, &val, base); + *out = static_cast<int_type>(val); + } else { // 32-bit + uint32_t val; + parsed = numbers_internal::safe_strtou32_base(s, &val, base); + *out = static_cast<int_type>(val); + } + } + return parsed; +} + +// FastHexToBufferZeroPad16() +// +// Outputs `val` into `out` as if by `snprintf(out, 17, "%016x", val)` but +// without the terminating null character. Thus `out` must be of length >= 16. +// Returns the number of non-pad digits of the output (it can never be zero +// since 0 has one digit). +inline size_t FastHexToBufferZeroPad16(uint64_t val, char* out) { #ifdef _Y__SSE4_2__ uint64_t be = y_absl::big_endian::FromHost64(val); - const auto kNibbleMask = _mm_set1_epi8(0xf); - const auto kHexDigits = _mm_setr_epi8('0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); - auto v = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&be)); // load lo dword - auto v4 = _mm_srli_epi64(v, 4); // shift 4 right - auto il = _mm_unpacklo_epi8(v4, v); // interleave bytes - auto m = _mm_and_si128(il, kNibbleMask); // mask out nibbles - auto hexchars = _mm_shuffle_epi8(kHexDigits, m); // hex chars - _mm_storeu_si128(reinterpret_cast<__m128i*>(out), hexchars); -#else - for (int i = 0; i < 8; ++i) { - auto byte = (val >> (56 - 8 * i)) & 0xFF; + const auto kNibbleMask = _mm_set1_epi8(0xf); + const auto kHexDigits = _mm_setr_epi8('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); + auto v = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&be)); // load lo dword + auto v4 = _mm_srli_epi64(v, 4); // shift 4 right + auto il = _mm_unpacklo_epi8(v4, v); // interleave bytes + auto m = _mm_and_si128(il, kNibbleMask); // mask out nibbles + auto hexchars = _mm_shuffle_epi8(kHexDigits, m); // hex chars + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), hexchars); +#else + for (int i = 0; i < 8; ++i) { + auto byte = (val >> (56 - 8 * i)) & 0xFF; auto* hex = &y_absl::numbers_internal::kHexTable[byte * 2]; - std::memcpy(out + 2 * i, hex, 2); - } -#endif - // | 0x1 so that even 0 has 1 digit. + std::memcpy(out + 2 * i, hex, 2); + } +#endif + // | 0x1 so that even 0 has 1 digit. return 16 - countl_zero(val | 0x1) / 4; -} - -} // namespace numbers_internal - -template <typename int_type> +} + +} // namespace numbers_internal + +template <typename int_type> ABSL_MUST_USE_RESULT bool SimpleAtoi(y_absl::string_view str, int_type* out) { - return numbers_internal::safe_strtoi_base(str, out, 10); -} - + return numbers_internal::safe_strtoi_base(str, out, 10); +} + ABSL_MUST_USE_RESULT inline bool SimpleAtoi(y_absl::string_view str, y_absl::int128* out) { return numbers_internal::safe_strto128_base(str, out, 10); @@ -284,9 +284,9 @@ ABSL_MUST_USE_RESULT inline bool SimpleAtoi(y_absl::string_view str, ABSL_MUST_USE_RESULT inline bool SimpleAtoi(y_absl::string_view str, y_absl::uint128* out) { - return numbers_internal::safe_strtou128_base(str, out, 10); -} - + return numbers_internal::safe_strtou128_base(str, out, 10); +} + template <typename int_type> ABSL_MUST_USE_RESULT bool SimpleHexAtoi(y_absl::string_view str, int_type* out) { return numbers_internal::safe_strtoi_base(str, out, 16); @@ -304,5 +304,5 @@ ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(y_absl::string_view str, ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_NUMBERS_H_ + +#endif // ABSL_STRINGS_NUMBERS_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.cc index 9e11702eae..3d6ee98d3b 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.cc @@ -1,246 +1,246 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/str_cat.h" - -#include <assert.h> - -#include <algorithm> -#include <cstdint> -#include <cstring> - + +#include <assert.h> + +#include <algorithm> +#include <cstdint> +#include <cstring> + #include "y_absl/strings/ascii.h" #include "y_absl/strings/internal/resize_uninitialized.h" #include "y_absl/strings/numbers.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -AlphaNum::AlphaNum(Hex hex) { - static_assert(numbers_internal::kFastToBufferSize >= 32, - "This function only works when output buffer >= 32 bytes long"); - char* const end = &digits_[numbers_internal::kFastToBufferSize]; - auto real_width = + +AlphaNum::AlphaNum(Hex hex) { + static_assert(numbers_internal::kFastToBufferSize >= 32, + "This function only works when output buffer >= 32 bytes long"); + char* const end = &digits_[numbers_internal::kFastToBufferSize]; + auto real_width = y_absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16); - if (real_width >= hex.width) { + if (real_width >= hex.width) { piece_ = y_absl::string_view(end - real_width, real_width); - } else { - // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and - // max pad width can be up to 20. - std::memset(end - 32, hex.fill, 16); - // Patch up everything else up to the real_width. - std::memset(end - real_width - 16, hex.fill, 16); + } else { + // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and + // max pad width can be up to 20. + std::memset(end - 32, hex.fill, 16); + // Patch up everything else up to the real_width. + std::memset(end - real_width - 16, hex.fill, 16); piece_ = y_absl::string_view(end - hex.width, hex.width); - } -} - -AlphaNum::AlphaNum(Dec dec) { - assert(dec.width <= numbers_internal::kFastToBufferSize); - char* const end = &digits_[numbers_internal::kFastToBufferSize]; - char* const minfill = end - dec.width; - char* writer = end; - uint64_t value = dec.value; - bool neg = dec.neg; - while (value > 9) { - *--writer = '0' + (value % 10); - value /= 10; - } - *--writer = '0' + value; - if (neg) *--writer = '-'; - - ptrdiff_t fillers = writer - minfill; - if (fillers > 0) { - // Tricky: if the fill character is ' ', then it's <fill><+/-><digits> - // But...: if the fill character is '0', then it's <+/-><fill><digits> - bool add_sign_again = false; - if (neg && dec.fill == '0') { // If filling with '0', - ++writer; // ignore the sign we just added - add_sign_again = true; // and re-add the sign later. - } - writer -= fillers; - std::fill_n(writer, fillers, dec.fill); - if (add_sign_again) *--writer = '-'; - } - + } +} + +AlphaNum::AlphaNum(Dec dec) { + assert(dec.width <= numbers_internal::kFastToBufferSize); + char* const end = &digits_[numbers_internal::kFastToBufferSize]; + char* const minfill = end - dec.width; + char* writer = end; + uint64_t value = dec.value; + bool neg = dec.neg; + while (value > 9) { + *--writer = '0' + (value % 10); + value /= 10; + } + *--writer = '0' + value; + if (neg) *--writer = '-'; + + ptrdiff_t fillers = writer - minfill; + if (fillers > 0) { + // Tricky: if the fill character is ' ', then it's <fill><+/-><digits> + // But...: if the fill character is '0', then it's <+/-><fill><digits> + bool add_sign_again = false; + if (neg && dec.fill == '0') { // If filling with '0', + ++writer; // ignore the sign we just added + add_sign_again = true; // and re-add the sign later. + } + writer -= fillers; + std::fill_n(writer, fillers, dec.fill); + if (add_sign_again) *--writer = '-'; + } + piece_ = y_absl::string_view(writer, end - writer); -} - -// ---------------------------------------------------------------------- -// StrCat() -// This merges the given strings or integers, with no delimiter. This -// is designed to be the fastest possible way to construct a string out -// of a mix of raw C strings, string_views, strings, and integer values. -// ---------------------------------------------------------------------- - -// Append is merely a version of memcpy that returns the address of the byte -// after the area just overwritten. -static char* Append(char* out, const AlphaNum& x) { - // memcpy is allowed to overwrite arbitrary memory, so doing this after the - // call would force an extra fetch of x.size(). - char* after = out + x.size(); - if (x.size() != 0) { - memcpy(out, x.data(), x.size()); - } - return after; -} - +} + +// ---------------------------------------------------------------------- +// StrCat() +// This merges the given strings or integers, with no delimiter. This +// is designed to be the fastest possible way to construct a string out +// of a mix of raw C strings, string_views, strings, and integer values. +// ---------------------------------------------------------------------- + +// Append is merely a version of memcpy that returns the address of the byte +// after the area just overwritten. +static char* Append(char* out, const AlphaNum& x) { + // memcpy is allowed to overwrite arbitrary memory, so doing this after the + // call would force an extra fetch of x.size(). + char* after = out + x.size(); + if (x.size() != 0) { + memcpy(out, x.data(), x.size()); + } + return after; +} + TString StrCat(const AlphaNum& a, const AlphaNum& b) { TString result; y_absl::strings_internal::STLStringResizeUninitialized(&result, - a.size() + b.size()); - char* const begin = &result[0]; - char* out = begin; - out = Append(out, a); - out = Append(out, b); - assert(out == begin + result.size()); - return result; -} - + a.size() + b.size()); + char* const begin = &result[0]; + char* out = begin; + out = Append(out, a); + out = Append(out, b); + assert(out == begin + result.size()); + return result; +} + TString StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) { TString result; - strings_internal::STLStringResizeUninitialized( - &result, a.size() + b.size() + c.size()); - char* const begin = &result[0]; - char* out = begin; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - assert(out == begin + result.size()); - return result; -} - + strings_internal::STLStringResizeUninitialized( + &result, a.size() + b.size() + c.size()); + char* const begin = &result[0]; + char* out = begin; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + assert(out == begin + result.size()); + return result; +} + TString StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, - const AlphaNum& d) { + const AlphaNum& d) { TString result; - strings_internal::STLStringResizeUninitialized( - &result, a.size() + b.size() + c.size() + d.size()); - char* const begin = &result[0]; - char* out = begin; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - out = Append(out, d); - assert(out == begin + result.size()); - return result; -} - -namespace strings_internal { - -// Do not call directly - these are not part of the public API. + strings_internal::STLStringResizeUninitialized( + &result, a.size() + b.size() + c.size() + d.size()); + char* const begin = &result[0]; + char* out = begin; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + out = Append(out, d); + assert(out == begin + result.size()); + return result; +} + +namespace strings_internal { + +// Do not call directly - these are not part of the public API. TString CatPieces(std::initializer_list<y_absl::string_view> pieces) { TString result; - size_t total_size = 0; + size_t total_size = 0; for (const y_absl::string_view& piece : pieces) total_size += piece.size(); - strings_internal::STLStringResizeUninitialized(&result, total_size); - - char* const begin = &result[0]; - char* out = begin; + strings_internal::STLStringResizeUninitialized(&result, total_size); + + char* const begin = &result[0]; + char* out = begin; for (const y_absl::string_view& piece : pieces) { - const size_t this_size = piece.size(); - if (this_size != 0) { - memcpy(out, piece.data(), this_size); - out += this_size; - } - } - assert(out == begin + result.size()); - return result; -} - + const size_t this_size = piece.size(); + if (this_size != 0) { + memcpy(out, piece.data(), this_size); + out += this_size; + } + } + assert(out == begin + result.size()); + return result; +} + // It's possible to call StrAppend with an y_absl::string_view that is itself a -// fragment of the string we're appending to. However the results of this are -// random. Therefore, check for this in debug mode. Use unsigned math so we -// only have to do one comparison. Note, there's an exception case: appending an -// empty string is always allowed. -#define ASSERT_NO_OVERLAP(dest, src) \ - assert(((src).size() == 0) || \ - (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size()))) - +// fragment of the string we're appending to. However the results of this are +// random. Therefore, check for this in debug mode. Use unsigned math so we +// only have to do one comparison. Note, there's an exception case: appending an +// empty string is always allowed. +#define ASSERT_NO_OVERLAP(dest, src) \ + assert(((src).size() == 0) || \ + (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size()))) + void AppendPieces(TString* dest, std::initializer_list<y_absl::string_view> pieces) { - size_t old_size = dest->size(); - size_t total_size = old_size; + size_t old_size = dest->size(); + size_t total_size = old_size; for (const y_absl::string_view& piece : pieces) { - ASSERT_NO_OVERLAP(*dest, piece); - total_size += piece.size(); - } + ASSERT_NO_OVERLAP(*dest, piece); + total_size += piece.size(); + } strings_internal::STLStringResizeUninitializedAmortized(dest, total_size); - - char* const begin = &(*dest)[0]; - char* out = begin + old_size; + + char* const begin = &(*dest)[0]; + char* out = begin + old_size; for (const y_absl::string_view& piece : pieces) { - const size_t this_size = piece.size(); - if (this_size != 0) { - memcpy(out, piece.data(), this_size); - out += this_size; - } - } - assert(out == begin + dest->size()); -} - -} // namespace strings_internal - + const size_t this_size = piece.size(); + if (this_size != 0) { + memcpy(out, piece.data(), this_size); + out += this_size; + } + } + assert(out == begin + dest->size()); +} + +} // namespace strings_internal + void StrAppend(TString* dest, const AlphaNum& a) { - ASSERT_NO_OVERLAP(*dest, a); - dest->append(a.data(), a.size()); -} - + ASSERT_NO_OVERLAP(*dest, a); + dest->append(a.data(), a.size()); +} + void StrAppend(TString* dest, const AlphaNum& a, const AlphaNum& b) { - ASSERT_NO_OVERLAP(*dest, a); - ASSERT_NO_OVERLAP(*dest, b); + ASSERT_NO_OVERLAP(*dest, a); + ASSERT_NO_OVERLAP(*dest, b); TString::size_type old_size = dest->size(); strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - assert(out == begin + dest->size()); -} - + dest, old_size + a.size() + b.size()); + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + out = Append(out, a); + out = Append(out, b); + assert(out == begin + dest->size()); +} + void StrAppend(TString* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c) { - ASSERT_NO_OVERLAP(*dest, a); - ASSERT_NO_OVERLAP(*dest, b); - ASSERT_NO_OVERLAP(*dest, c); + const AlphaNum& c) { + ASSERT_NO_OVERLAP(*dest, a); + ASSERT_NO_OVERLAP(*dest, b); + ASSERT_NO_OVERLAP(*dest, c); TString::size_type old_size = dest->size(); strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size() + c.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - assert(out == begin + dest->size()); -} - + dest, old_size + a.size() + b.size() + c.size()); + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + assert(out == begin + dest->size()); +} + void StrAppend(TString* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d) { - ASSERT_NO_OVERLAP(*dest, a); - ASSERT_NO_OVERLAP(*dest, b); - ASSERT_NO_OVERLAP(*dest, c); - ASSERT_NO_OVERLAP(*dest, d); + const AlphaNum& c, const AlphaNum& d) { + ASSERT_NO_OVERLAP(*dest, a); + ASSERT_NO_OVERLAP(*dest, b); + ASSERT_NO_OVERLAP(*dest, c); + ASSERT_NO_OVERLAP(*dest, d); TString::size_type old_size = dest->size(); strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size() + c.size() + d.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - out = Append(out, d); - assert(out == begin + dest->size()); -} - + dest, old_size + a.size() + b.size() + c.size() + d.size()); + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + out = Append(out, d); + assert(out == begin + dest->size()); +} + ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.h index a77c9ae906..29c50dd4f7 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.h @@ -1,411 +1,411 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: str_cat.h -// ----------------------------------------------------------------------------- -// -// This package contains functions for efficiently concatenating and appending -// strings: `StrCat()` and `StrAppend()`. Most of the work within these routines -// is actually handled through use of a special AlphaNum type, which was -// designed to be used as a parameter type that efficiently manages conversion -// to strings and avoids copies in the above operations. -// -// Any routine accepting either a string or a number may accept `AlphaNum`. -// The basic idea is that by accepting a `const AlphaNum &` as an argument -// to your function, your callers will automagically convert bools, integers, -// and floating point values to strings for you. -// +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: str_cat.h +// ----------------------------------------------------------------------------- +// +// This package contains functions for efficiently concatenating and appending +// strings: `StrCat()` and `StrAppend()`. Most of the work within these routines +// is actually handled through use of a special AlphaNum type, which was +// designed to be used as a parameter type that efficiently manages conversion +// to strings and avoids copies in the above operations. +// +// Any routine accepting either a string or a number may accept `AlphaNum`. +// The basic idea is that by accepting a `const AlphaNum &` as an argument +// to your function, your callers will automagically convert bools, integers, +// and floating point values to strings for you. +// // NOTE: Use of `AlphaNum` outside of the //y_absl/strings package is unsupported -// except for the specific case of function parameters of type `AlphaNum` or -// `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a -// stack variable is not supported. -// -// Conversion from 8-bit values is not accepted because, if it were, then an -// attempt to pass ':' instead of ":" might result in a 58 ending up in your -// result. -// -// Bools convert to "0" or "1". Pointers to types other than `char *` are not -// valid inputs. No output is generated for null `char *` pointers. -// -// Floating point numbers are formatted with six-digit precision, which is -// the default for "std::cout <<" or printf "%g" (the same as "%.6g"). -// -// You can convert to hexadecimal output rather than decimal output using the -// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to -// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using -// a `PadSpec` enum. -// -// ----------------------------------------------------------------------------- - -#ifndef ABSL_STRINGS_STR_CAT_H_ -#define ABSL_STRINGS_STR_CAT_H_ - -#include <array> -#include <cstdint> +// except for the specific case of function parameters of type `AlphaNum` or +// `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a +// stack variable is not supported. +// +// Conversion from 8-bit values is not accepted because, if it were, then an +// attempt to pass ':' instead of ":" might result in a 58 ending up in your +// result. +// +// Bools convert to "0" or "1". Pointers to types other than `char *` are not +// valid inputs. No output is generated for null `char *` pointers. +// +// Floating point numbers are formatted with six-digit precision, which is +// the default for "std::cout <<" or printf "%g" (the same as "%.6g"). +// +// You can convert to hexadecimal output rather than decimal output using the +// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to +// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using +// a `PadSpec` enum. +// +// ----------------------------------------------------------------------------- + +#ifndef ABSL_STRINGS_STR_CAT_H_ +#define ABSL_STRINGS_STR_CAT_H_ + +#include <array> +#include <cstdint> #include <util/generic/string.h> -#include <type_traits> -#include <vector> - +#include <type_traits> +#include <vector> + #include "y_absl/base/port.h" #include "y_absl/strings/numbers.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -namespace strings_internal { -// AlphaNumBuffer allows a way to pass a string to StrCat without having to do -// memory allocation. It is simply a pair of a fixed-size character array, and + +namespace strings_internal { +// AlphaNumBuffer allows a way to pass a string to StrCat without having to do +// memory allocation. It is simply a pair of a fixed-size character array, and // a size. Please don't use outside of y_absl, yet. -template <size_t max_size> -struct AlphaNumBuffer { - std::array<char, max_size> data; - size_t size; -}; - -} // namespace strings_internal - -// Enum that specifies the number of significant digits to return in a `Hex` or -// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example, -// would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value -// would produce hexadecimal strings such as " a"," f". -enum PadSpec : uint8_t { - kNoPad = 1, - kZeroPad2, - kZeroPad3, - kZeroPad4, - kZeroPad5, - kZeroPad6, - kZeroPad7, - kZeroPad8, - kZeroPad9, - kZeroPad10, - kZeroPad11, - kZeroPad12, - kZeroPad13, - kZeroPad14, - kZeroPad15, - kZeroPad16, - kZeroPad17, - kZeroPad18, - kZeroPad19, - kZeroPad20, - - kSpacePad2 = kZeroPad2 + 64, - kSpacePad3, - kSpacePad4, - kSpacePad5, - kSpacePad6, - kSpacePad7, - kSpacePad8, - kSpacePad9, - kSpacePad10, - kSpacePad11, - kSpacePad12, - kSpacePad13, - kSpacePad14, - kSpacePad15, - kSpacePad16, - kSpacePad17, - kSpacePad18, - kSpacePad19, - kSpacePad20, -}; - -// ----------------------------------------------------------------------------- -// Hex -// ----------------------------------------------------------------------------- -// -// `Hex` stores a set of hexadecimal string conversion parameters for use -// within `AlphaNum` string conversions. -struct Hex { - uint64_t value; - uint8_t width; - char fill; - - template <typename Int> - explicit Hex( +template <size_t max_size> +struct AlphaNumBuffer { + std::array<char, max_size> data; + size_t size; +}; + +} // namespace strings_internal + +// Enum that specifies the number of significant digits to return in a `Hex` or +// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example, +// would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value +// would produce hexadecimal strings such as " a"," f". +enum PadSpec : uint8_t { + kNoPad = 1, + kZeroPad2, + kZeroPad3, + kZeroPad4, + kZeroPad5, + kZeroPad6, + kZeroPad7, + kZeroPad8, + kZeroPad9, + kZeroPad10, + kZeroPad11, + kZeroPad12, + kZeroPad13, + kZeroPad14, + kZeroPad15, + kZeroPad16, + kZeroPad17, + kZeroPad18, + kZeroPad19, + kZeroPad20, + + kSpacePad2 = kZeroPad2 + 64, + kSpacePad3, + kSpacePad4, + kSpacePad5, + kSpacePad6, + kSpacePad7, + kSpacePad8, + kSpacePad9, + kSpacePad10, + kSpacePad11, + kSpacePad12, + kSpacePad13, + kSpacePad14, + kSpacePad15, + kSpacePad16, + kSpacePad17, + kSpacePad18, + kSpacePad19, + kSpacePad20, +}; + +// ----------------------------------------------------------------------------- +// Hex +// ----------------------------------------------------------------------------- +// +// `Hex` stores a set of hexadecimal string conversion parameters for use +// within `AlphaNum` string conversions. +struct Hex { + uint64_t value; + uint8_t width; + char fill; + + template <typename Int> + explicit Hex( Int v, PadSpec spec = y_absl::kNoPad, - typename std::enable_if<sizeof(Int) == 1 && - !std::is_pointer<Int>::value>::type* = nullptr) - : Hex(spec, static_cast<uint8_t>(v)) {} - template <typename Int> - explicit Hex( + typename std::enable_if<sizeof(Int) == 1 && + !std::is_pointer<Int>::value>::type* = nullptr) + : Hex(spec, static_cast<uint8_t>(v)) {} + template <typename Int> + explicit Hex( Int v, PadSpec spec = y_absl::kNoPad, - typename std::enable_if<sizeof(Int) == 2 && - !std::is_pointer<Int>::value>::type* = nullptr) - : Hex(spec, static_cast<uint16_t>(v)) {} - template <typename Int> - explicit Hex( + typename std::enable_if<sizeof(Int) == 2 && + !std::is_pointer<Int>::value>::type* = nullptr) + : Hex(spec, static_cast<uint16_t>(v)) {} + template <typename Int> + explicit Hex( Int v, PadSpec spec = y_absl::kNoPad, - typename std::enable_if<sizeof(Int) == 4 && - !std::is_pointer<Int>::value>::type* = nullptr) - : Hex(spec, static_cast<uint32_t>(v)) {} - template <typename Int> - explicit Hex( + typename std::enable_if<sizeof(Int) == 4 && + !std::is_pointer<Int>::value>::type* = nullptr) + : Hex(spec, static_cast<uint32_t>(v)) {} + template <typename Int> + explicit Hex( Int v, PadSpec spec = y_absl::kNoPad, - typename std::enable_if<sizeof(Int) == 8 && - !std::is_pointer<Int>::value>::type* = nullptr) - : Hex(spec, static_cast<uint64_t>(v)) {} - template <typename Pointee> + typename std::enable_if<sizeof(Int) == 8 && + !std::is_pointer<Int>::value>::type* = nullptr) + : Hex(spec, static_cast<uint64_t>(v)) {} + template <typename Pointee> explicit Hex(Pointee* v, PadSpec spec = y_absl::kNoPad) - : Hex(spec, reinterpret_cast<uintptr_t>(v)) {} - - private: - Hex(PadSpec spec, uint64_t v) - : value(v), + : Hex(spec, reinterpret_cast<uintptr_t>(v)) {} + + private: + Hex(PadSpec spec, uint64_t v) + : value(v), width(spec == y_absl::kNoPad - ? 1 + ? 1 : spec >= y_absl::kSpacePad2 ? spec - y_absl::kSpacePad2 + 2 : spec - y_absl::kZeroPad2 + 2), fill(spec >= y_absl::kSpacePad2 ? ' ' : '0') {} -}; - -// ----------------------------------------------------------------------------- -// Dec -// ----------------------------------------------------------------------------- -// -// `Dec` stores a set of decimal string conversion parameters for use -// within `AlphaNum` string conversions. Dec is slower than the default -// integer conversion, so use it only if you need padding. -struct Dec { - uint64_t value; - uint8_t width; - char fill; - bool neg; - - template <typename Int> +}; + +// ----------------------------------------------------------------------------- +// Dec +// ----------------------------------------------------------------------------- +// +// `Dec` stores a set of decimal string conversion parameters for use +// within `AlphaNum` string conversions. Dec is slower than the default +// integer conversion, so use it only if you need padding. +struct Dec { + uint64_t value; + uint8_t width; + char fill; + bool neg; + + template <typename Int> explicit Dec(Int v, PadSpec spec = y_absl::kNoPad, - typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr) - : value(v >= 0 ? static_cast<uint64_t>(v) - : uint64_t{0} - static_cast<uint64_t>(v)), + typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr) + : value(v >= 0 ? static_cast<uint64_t>(v) + : uint64_t{0} - static_cast<uint64_t>(v)), width(spec == y_absl::kNoPad - ? 1 + ? 1 : spec >= y_absl::kSpacePad2 ? spec - y_absl::kSpacePad2 + 2 : spec - y_absl::kZeroPad2 + 2), fill(spec >= y_absl::kSpacePad2 ? ' ' : '0'), - neg(v < 0) {} -}; - -// ----------------------------------------------------------------------------- -// AlphaNum -// ----------------------------------------------------------------------------- -// -// The `AlphaNum` class acts as the main parameter type for `StrCat()` and -// `StrAppend()`, providing efficient conversion of numeric, boolean, and -// hexadecimal values (through the `Hex` type) into strings. - -class AlphaNum { - public: - // No bool ctor -- bools convert to an integral type. - // A bool ctor would also convert incoming pointers (bletch). - - AlphaNum(int x) // NOLINT(runtime/explicit) - : piece_(digits_, - numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} - AlphaNum(unsigned int x) // NOLINT(runtime/explicit) - : piece_(digits_, - numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} - AlphaNum(long x) // NOLINT(*) - : piece_(digits_, - numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} - AlphaNum(unsigned long x) // NOLINT(*) - : piece_(digits_, - numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} - AlphaNum(long long x) // NOLINT(*) - : piece_(digits_, - numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} - AlphaNum(unsigned long long x) // NOLINT(*) - : piece_(digits_, - numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} - - AlphaNum(float f) // NOLINT(runtime/explicit) - : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} - AlphaNum(double f) // NOLINT(runtime/explicit) - : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} - - AlphaNum(Hex hex); // NOLINT(runtime/explicit) - AlphaNum(Dec dec); // NOLINT(runtime/explicit) - - template <size_t size> - AlphaNum( // NOLINT(runtime/explicit) - const strings_internal::AlphaNumBuffer<size>& buf) - : piece_(&buf.data[0], buf.size) {} - - AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit) + neg(v < 0) {} +}; + +// ----------------------------------------------------------------------------- +// AlphaNum +// ----------------------------------------------------------------------------- +// +// The `AlphaNum` class acts as the main parameter type for `StrCat()` and +// `StrAppend()`, providing efficient conversion of numeric, boolean, and +// hexadecimal values (through the `Hex` type) into strings. + +class AlphaNum { + public: + // No bool ctor -- bools convert to an integral type. + // A bool ctor would also convert incoming pointers (bletch). + + AlphaNum(int x) // NOLINT(runtime/explicit) + : piece_(digits_, + numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} + AlphaNum(unsigned int x) // NOLINT(runtime/explicit) + : piece_(digits_, + numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} + AlphaNum(long x) // NOLINT(*) + : piece_(digits_, + numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} + AlphaNum(unsigned long x) // NOLINT(*) + : piece_(digits_, + numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} + AlphaNum(long long x) // NOLINT(*) + : piece_(digits_, + numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} + AlphaNum(unsigned long long x) // NOLINT(*) + : piece_(digits_, + numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} + + AlphaNum(float f) // NOLINT(runtime/explicit) + : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} + AlphaNum(double f) // NOLINT(runtime/explicit) + : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} + + AlphaNum(Hex hex); // NOLINT(runtime/explicit) + AlphaNum(Dec dec); // NOLINT(runtime/explicit) + + template <size_t size> + AlphaNum( // NOLINT(runtime/explicit) + const strings_internal::AlphaNumBuffer<size>& buf) + : piece_(&buf.data[0], buf.size) {} + + AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit) AlphaNum(y_absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit) - - template <typename Allocator> - AlphaNum( // NOLINT(runtime/explicit) - const std::basic_string<char, std::char_traits<char>, Allocator>& str) - : piece_(str) {} - + + template <typename Allocator> + AlphaNum( // NOLINT(runtime/explicit) + const std::basic_string<char, std::char_traits<char>, Allocator>& str) + : piece_(str) {} + AlphaNum(const TString& str) : piece_(str.data(), str.size()) {} // Use string literals ":" instead of character literals ':'. - AlphaNum(char c) = delete; // NOLINT(runtime/explicit) - - AlphaNum(const AlphaNum&) = delete; - AlphaNum& operator=(const AlphaNum&) = delete; - + AlphaNum(char c) = delete; // NOLINT(runtime/explicit) + + AlphaNum(const AlphaNum&) = delete; + AlphaNum& operator=(const AlphaNum&) = delete; + y_absl::string_view::size_type size() const { return piece_.size(); } - const char* data() const { return piece_.data(); } + const char* data() const { return piece_.data(); } y_absl::string_view Piece() const { return piece_; } - - // Normal enums are already handled by the integer formatters. - // This overload matches only scoped enums. - template <typename T, - typename = typename std::enable_if< - std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type> - AlphaNum(T e) // NOLINT(runtime/explicit) - : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {} - - // vector<bool>::reference and const_reference require special help to - // convert to `AlphaNum` because it requires two user defined conversions. - template < - typename T, - typename std::enable_if< - std::is_class<T>::value && - (std::is_same<T, std::vector<bool>::reference>::value || - std::is_same<T, std::vector<bool>::const_reference>::value)>::type* = - nullptr> - AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {} // NOLINT(runtime/explicit) - - private: + + // Normal enums are already handled by the integer formatters. + // This overload matches only scoped enums. + template <typename T, + typename = typename std::enable_if< + std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type> + AlphaNum(T e) // NOLINT(runtime/explicit) + : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {} + + // vector<bool>::reference and const_reference require special help to + // convert to `AlphaNum` because it requires two user defined conversions. + template < + typename T, + typename std::enable_if< + std::is_class<T>::value && + (std::is_same<T, std::vector<bool>::reference>::value || + std::is_same<T, std::vector<bool>::const_reference>::value)>::type* = + nullptr> + AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {} // NOLINT(runtime/explicit) + + private: y_absl::string_view piece_; - char digits_[numbers_internal::kFastToBufferSize]; -}; - -// ----------------------------------------------------------------------------- -// StrCat() -// ----------------------------------------------------------------------------- -// -// Merges given strings or numbers, using no delimiter(s), returning the merged -// result as a string. -// -// `StrCat()` is designed to be the fastest possible way to construct a string -// out of a mix of raw C strings, string_views, strings, bool values, -// and numeric values. -// -// Don't use `StrCat()` for user-visible strings. The localization process -// works poorly on strings built up out of fragments. -// -// For clarity and performance, don't use `StrCat()` when appending to a -// string. Use `StrAppend()` instead. In particular, avoid using any of these -// (anti-)patterns: -// -// str.append(StrCat(...)) -// str += StrCat(...) -// str = StrCat(str, ...) -// -// The last case is the worst, with a potential to change a loop -// from a linear time operation with O(1) dynamic allocations into a -// quadratic time operation with O(n) dynamic allocations. -// -// See `StrAppend()` below for more information. - -namespace strings_internal { - -// Do not call directly - this is not part of the public API. + char digits_[numbers_internal::kFastToBufferSize]; +}; + +// ----------------------------------------------------------------------------- +// StrCat() +// ----------------------------------------------------------------------------- +// +// Merges given strings or numbers, using no delimiter(s), returning the merged +// result as a string. +// +// `StrCat()` is designed to be the fastest possible way to construct a string +// out of a mix of raw C strings, string_views, strings, bool values, +// and numeric values. +// +// Don't use `StrCat()` for user-visible strings. The localization process +// works poorly on strings built up out of fragments. +// +// For clarity and performance, don't use `StrCat()` when appending to a +// string. Use `StrAppend()` instead. In particular, avoid using any of these +// (anti-)patterns: +// +// str.append(StrCat(...)) +// str += StrCat(...) +// str = StrCat(str, ...) +// +// The last case is the worst, with a potential to change a loop +// from a linear time operation with O(1) dynamic allocations into a +// quadratic time operation with O(n) dynamic allocations. +// +// See `StrAppend()` below for more information. + +namespace strings_internal { + +// Do not call directly - this is not part of the public API. TString CatPieces(std::initializer_list<y_absl::string_view> pieces); void AppendPieces(TString* dest, std::initializer_list<y_absl::string_view> pieces); - -} // namespace strings_internal - + +} // namespace strings_internal + ABSL_MUST_USE_RESULT inline TString StrCat() { return TString(); } - + ABSL_MUST_USE_RESULT inline TString StrCat(const AlphaNum& a) { return TString(a.data(), a.size()); -} - +} + ABSL_MUST_USE_RESULT TString StrCat(const AlphaNum& a, const AlphaNum& b); ABSL_MUST_USE_RESULT TString StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c); + const AlphaNum& c); ABSL_MUST_USE_RESULT TString StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d); - -// Support 5 or more arguments -template <typename... AV> + const AlphaNum& c, const AlphaNum& d); + +// Support 5 or more arguments +template <typename... AV> ABSL_MUST_USE_RESULT inline TString StrCat( - const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, - const AlphaNum& e, const AV&... args) { - return strings_internal::CatPieces( - {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), - static_cast<const AlphaNum&>(args).Piece()...}); -} - -// ----------------------------------------------------------------------------- -// StrAppend() -// ----------------------------------------------------------------------------- -// -// Appends a string or set of strings to an existing string, in a similar -// fashion to `StrCat()`. -// -// WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the -// a, b, c, parameters be a reference into str. For speed, `StrAppend()` does -// not try to check each of its input arguments to be sure that they are not -// a subset of the string being appended to. That is, while this will work: -// + const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, + const AlphaNum& e, const AV&... args) { + return strings_internal::CatPieces( + {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), + static_cast<const AlphaNum&>(args).Piece()...}); +} + +// ----------------------------------------------------------------------------- +// StrAppend() +// ----------------------------------------------------------------------------- +// +// Appends a string or set of strings to an existing string, in a similar +// fashion to `StrCat()`. +// +// WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the +// a, b, c, parameters be a reference into str. For speed, `StrAppend()` does +// not try to check each of its input arguments to be sure that they are not +// a subset of the string being appended to. That is, while this will work: +// // TString s = "foo"; -// s += s; -// -// This output is undefined: -// +// s += s; +// +// This output is undefined: +// // TString s = "foo"; -// StrAppend(&s, s); -// +// StrAppend(&s, s); +// // This output is undefined as well, since `y_absl::string_view` does not own its -// data: -// +// data: +// // TString s = "foobar"; // y_absl::string_view p = s; -// StrAppend(&s, p); - +// StrAppend(&s, p); + inline void StrAppend(TString*) {} void StrAppend(TString* dest, const AlphaNum& a); void StrAppend(TString* dest, const AlphaNum& a, const AlphaNum& b); void StrAppend(TString* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c); + const AlphaNum& c); void StrAppend(TString* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d); - -// Support 5 or more arguments -template <typename... AV> + const AlphaNum& c, const AlphaNum& d); + +// Support 5 or more arguments +template <typename... AV> inline void StrAppend(TString* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, - const AV&... args) { - strings_internal::AppendPieces( - dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), - static_cast<const AlphaNum&>(args).Piece()...}); -} - -// Helper function for the future StrCat default floating-point format, %.6g -// This is fast. -inline strings_internal::AlphaNumBuffer< - numbers_internal::kSixDigitsToBufferSize> -SixDigits(double d) { - strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize> - result; - result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]); - return result; -} - + const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, + const AV&... args) { + strings_internal::AppendPieces( + dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), + static_cast<const AlphaNum&>(args).Piece()...}); +} + +// Helper function for the future StrCat default floating-point format, %.6g +// This is fast. +inline strings_internal::AlphaNumBuffer< + numbers_internal::kSixDigitsToBufferSize> +SixDigits(double d) { + strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize> + result; + result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]); + return result; +} + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_STR_CAT_H_ + +#endif // ABSL_STRINGS_STR_CAT_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_format.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_format.h index 4079f38fb4..77149b29de 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_format.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_format.h @@ -1,286 +1,286 @@ -// -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: str_format.h -// ----------------------------------------------------------------------------- -// -// The `str_format` library is a typesafe replacement for the family of -// `printf()` string formatting routines within the `<cstdio>` standard library +// +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: str_format.h +// ----------------------------------------------------------------------------- +// +// The `str_format` library is a typesafe replacement for the family of +// `printf()` string formatting routines within the `<cstdio>` standard library // header. Like the `printf` family, `str_format` uses a "format string" to -// perform argument substitutions based on types. See the `FormatSpec` section -// below for format string documentation. -// -// Example: -// +// perform argument substitutions based on types. See the `FormatSpec` section +// below for format string documentation. +// +// Example: +// // TString s = y_absl::StrFormat( -// "%s %s You have $%d!", "Hello", name, dollars); -// -// The library consists of the following basic utilities: -// +// "%s %s You have $%d!", "Hello", name, dollars); +// +// The library consists of the following basic utilities: +// // * `y_absl::StrFormat()`, a type-safe replacement for `std::sprintf()`, to -// write a format string to a `string` value. +// write a format string to a `string` value. // * `y_absl::StrAppendFormat()` to append a format string to a `string` // * `y_absl::StreamFormat()` to more efficiently write a format string to a -// stream, such as`std::cout`. +// stream, such as`std::cout`. // * `y_absl::PrintF()`, `y_absl::FPrintF()` and `y_absl::SNPrintF()` as -// replacements for `std::printf()`, `std::fprintf()` and `std::snprintf()`. -// -// Note: a version of `std::sprintf()` is not supported as it is -// generally unsafe due to buffer overflows. -// -// Additionally, you can provide a format string (and its associated arguments) -// using one of the following abstractions: -// -// * A `FormatSpec` class template fully encapsulates a format string and its -// type arguments and is usually provided to `str_format` functions as a -// variadic argument of type `FormatSpec<Arg...>`. The `FormatSpec<Args...>` -// template is evaluated at compile-time, providing type safety. -// * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled -// format string for a specific set of type(s), and which can be passed -// between API boundaries. (The `FormatSpec` type should not be used -// directly except as an argument type for wrapper functions.) -// -// The `str_format` library provides the ability to output its format strings to -// arbitrary sink types: -// -// * A generic `Format()` function to write outputs to arbitrary sink types, +// replacements for `std::printf()`, `std::fprintf()` and `std::snprintf()`. +// +// Note: a version of `std::sprintf()` is not supported as it is +// generally unsafe due to buffer overflows. +// +// Additionally, you can provide a format string (and its associated arguments) +// using one of the following abstractions: +// +// * A `FormatSpec` class template fully encapsulates a format string and its +// type arguments and is usually provided to `str_format` functions as a +// variadic argument of type `FormatSpec<Arg...>`. The `FormatSpec<Args...>` +// template is evaluated at compile-time, providing type safety. +// * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled +// format string for a specific set of type(s), and which can be passed +// between API boundaries. (The `FormatSpec` type should not be used +// directly except as an argument type for wrapper functions.) +// +// The `str_format` library provides the ability to output its format strings to +// arbitrary sink types: +// +// * A generic `Format()` function to write outputs to arbitrary sink types, // which must implement a `FormatRawSink` interface. -// -// * A `FormatUntyped()` function that is similar to `Format()` except it is -// loosely typed. `FormatUntyped()` is not a template and does not perform -// any compile-time checking of the format string; instead, it returns a -// boolean from a runtime check. -// -// In addition, the `str_format` library provides extension points for +// +// * A `FormatUntyped()` function that is similar to `Format()` except it is +// loosely typed. `FormatUntyped()` is not a template and does not perform +// any compile-time checking of the format string; instead, it returns a +// boolean from a runtime check. +// +// In addition, the `str_format` library provides extension points for // augmenting formatting to new types. See "StrFormat Extensions" below. - -#ifndef ABSL_STRINGS_STR_FORMAT_H_ -#define ABSL_STRINGS_STR_FORMAT_H_ - -#include <cstdio> + +#ifndef ABSL_STRINGS_STR_FORMAT_H_ +#define ABSL_STRINGS_STR_FORMAT_H_ + +#include <cstdio> #include <util/generic/string.h> - + #include "y_absl/strings/internal/str_format/arg.h" // IWYU pragma: export #include "y_absl/strings/internal/str_format/bind.h" // IWYU pragma: export #include "y_absl/strings/internal/str_format/checker.h" // IWYU pragma: export #include "y_absl/strings/internal/str_format/extension.h" // IWYU pragma: export #include "y_absl/strings/internal/str_format/parser.h" // IWYU pragma: export - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -// UntypedFormatSpec -// -// A type-erased class that can be used directly within untyped API entry -// points. An `UntypedFormatSpec` is specifically used as an argument to -// `FormatUntyped()`. -// -// Example: -// + +// UntypedFormatSpec +// +// A type-erased class that can be used directly within untyped API entry +// points. An `UntypedFormatSpec` is specifically used as an argument to +// `FormatUntyped()`. +// +// Example: +// // y_absl::UntypedFormatSpec format("%d"); // TString out; // CHECK(y_absl::FormatUntyped(&out, format, {y_absl::FormatArg(1)})); -class UntypedFormatSpec { - public: - UntypedFormatSpec() = delete; - UntypedFormatSpec(const UntypedFormatSpec&) = delete; - UntypedFormatSpec& operator=(const UntypedFormatSpec&) = delete; - - explicit UntypedFormatSpec(string_view s) : spec_(s) {} - - protected: - explicit UntypedFormatSpec(const str_format_internal::ParsedFormatBase* pc) - : spec_(pc) {} - - private: - friend str_format_internal::UntypedFormatSpecImpl; - str_format_internal::UntypedFormatSpecImpl spec_; -}; - -// FormatStreamed() -// -// Takes a streamable argument and returns an object that can print it -// with '%s'. Allows printing of types that have an `operator<<` but no -// intrinsic type support within `StrFormat()` itself. -// -// Example: -// +class UntypedFormatSpec { + public: + UntypedFormatSpec() = delete; + UntypedFormatSpec(const UntypedFormatSpec&) = delete; + UntypedFormatSpec& operator=(const UntypedFormatSpec&) = delete; + + explicit UntypedFormatSpec(string_view s) : spec_(s) {} + + protected: + explicit UntypedFormatSpec(const str_format_internal::ParsedFormatBase* pc) + : spec_(pc) {} + + private: + friend str_format_internal::UntypedFormatSpecImpl; + str_format_internal::UntypedFormatSpecImpl spec_; +}; + +// FormatStreamed() +// +// Takes a streamable argument and returns an object that can print it +// with '%s'. Allows printing of types that have an `operator<<` but no +// intrinsic type support within `StrFormat()` itself. +// +// Example: +// // y_absl::StrFormat("%s", y_absl::FormatStreamed(obj)); -template <typename T> -str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) { - return str_format_internal::StreamedWrapper<T>(v); -} - -// FormatCountCapture -// -// This class provides a way to safely wrap `StrFormat()` captures of `%n` -// conversions, which denote the number of characters written by a formatting -// operation to this point, into an integer value. -// -// This wrapper is designed to allow safe usage of `%n` within `StrFormat(); in -// the `printf()` family of functions, `%n` is not safe to use, as the `int *` -// buffer can be used to capture arbitrary data. -// -// Example: -// -// int n = 0; +template <typename T> +str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) { + return str_format_internal::StreamedWrapper<T>(v); +} + +// FormatCountCapture +// +// This class provides a way to safely wrap `StrFormat()` captures of `%n` +// conversions, which denote the number of characters written by a formatting +// operation to this point, into an integer value. +// +// This wrapper is designed to allow safe usage of `%n` within `StrFormat(); in +// the `printf()` family of functions, `%n` is not safe to use, as the `int *` +// buffer can be used to capture arbitrary data. +// +// Example: +// +// int n = 0; // TString s = y_absl::StrFormat("%s%d%n", "hello", 123, // y_absl::FormatCountCapture(&n)); -// EXPECT_EQ(8, n); -class FormatCountCapture { - public: - explicit FormatCountCapture(int* p) : p_(p) {} - - private: - // FormatCountCaptureHelper is used to define FormatConvertImpl() for this - // class. - friend struct str_format_internal::FormatCountCaptureHelper; - // Unused() is here because of the false positive from -Wunused-private-field - // p_ is used in the templated function of the friend FormatCountCaptureHelper - // class. - int* Unused() { return p_; } - int* p_; -}; - -// FormatSpec -// -// The `FormatSpec` type defines the makeup of a format string within the -// `str_format` library. It is a variadic class template that is evaluated at -// compile-time, according to the format string and arguments that are passed to -// it. -// -// You should not need to manipulate this type directly. You should only name it -// if you are writing wrapper functions which accept format arguments that will -// be provided unmodified to functions in this library. Such a wrapper function -// might be a class method that provides format arguments and/or internally uses -// the result of formatting. -// -// For a `FormatSpec` to be valid at compile-time, it must be provided as -// either: -// +// EXPECT_EQ(8, n); +class FormatCountCapture { + public: + explicit FormatCountCapture(int* p) : p_(p) {} + + private: + // FormatCountCaptureHelper is used to define FormatConvertImpl() for this + // class. + friend struct str_format_internal::FormatCountCaptureHelper; + // Unused() is here because of the false positive from -Wunused-private-field + // p_ is used in the templated function of the friend FormatCountCaptureHelper + // class. + int* Unused() { return p_; } + int* p_; +}; + +// FormatSpec +// +// The `FormatSpec` type defines the makeup of a format string within the +// `str_format` library. It is a variadic class template that is evaluated at +// compile-time, according to the format string and arguments that are passed to +// it. +// +// You should not need to manipulate this type directly. You should only name it +// if you are writing wrapper functions which accept format arguments that will +// be provided unmodified to functions in this library. Such a wrapper function +// might be a class method that provides format arguments and/or internally uses +// the result of formatting. +// +// For a `FormatSpec` to be valid at compile-time, it must be provided as +// either: +// // * A `constexpr` literal or `y_absl::string_view`, which is how it most often -// used. -// * A `ParsedFormat` instantiation, which ensures the format string is -// valid before use. (See below.) -// -// Example: -// -// // Provided as a string literal. +// used. +// * A `ParsedFormat` instantiation, which ensures the format string is +// valid before use. (See below.) +// +// Example: +// +// // Provided as a string literal. // y_absl::StrFormat("Welcome to %s, Number %d!", "The Village", 6); -// +// // // Provided as a constexpr y_absl::string_view. // constexpr y_absl::string_view formatString = "Welcome to %s, Number %d!"; // y_absl::StrFormat(formatString, "The Village", 6); -// -// // Provided as a pre-compiled ParsedFormat object. -// // Note that this example is useful only for illustration purposes. +// +// // Provided as a pre-compiled ParsedFormat object. +// // Note that this example is useful only for illustration purposes. // y_absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!"); // y_absl::StrFormat(formatString, "TheVillage", 6); -// -// A format string generally follows the POSIX syntax as used within the POSIX -// `printf` specification. -// -// (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html.) -// -// In specific, the `FormatSpec` supports the following type specifiers: -// * `c` for characters -// * `s` for strings -// * `d` or `i` for integers -// * `o` for unsigned integer conversions into octal -// * `x` or `X` for unsigned integer conversions into hex -// * `u` for unsigned integers -// * `f` or `F` for floating point values into decimal notation -// * `e` or `E` for floating point values into exponential notation -// * `a` or `A` for floating point values into hex exponential notation -// * `g` or `G` for floating point values into decimal or exponential -// notation based on their precision -// * `p` for pointer address values -// * `n` for the special case of writing out the number of characters -// written to this point. The resulting value must be captured within an +// +// A format string generally follows the POSIX syntax as used within the POSIX +// `printf` specification. +// +// (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html.) +// +// In specific, the `FormatSpec` supports the following type specifiers: +// * `c` for characters +// * `s` for strings +// * `d` or `i` for integers +// * `o` for unsigned integer conversions into octal +// * `x` or `X` for unsigned integer conversions into hex +// * `u` for unsigned integers +// * `f` or `F` for floating point values into decimal notation +// * `e` or `E` for floating point values into exponential notation +// * `a` or `A` for floating point values into hex exponential notation +// * `g` or `G` for floating point values into decimal or exponential +// notation based on their precision +// * `p` for pointer address values +// * `n` for the special case of writing out the number of characters +// written to this point. The resulting value must be captured within an // `y_absl::FormatCountCapture` type. -// -// Implementation-defined behavior: -// * A null pointer provided to "%s" or "%p" is output as "(nil)". -// * A non-null pointer provided to "%p" is output in hex as if by %#x or -// %#lx. -// -// NOTE: `o`, `x\X` and `u` will convert signed values to their unsigned -// counterpart before formatting. -// -// Examples: -// "%c", 'a' -> "a" -// "%c", 32 -> " " -// "%s", "C" -> "C" +// +// Implementation-defined behavior: +// * A null pointer provided to "%s" or "%p" is output as "(nil)". +// * A non-null pointer provided to "%p" is output in hex as if by %#x or +// %#lx. +// +// NOTE: `o`, `x\X` and `u` will convert signed values to their unsigned +// counterpart before formatting. +// +// Examples: +// "%c", 'a' -> "a" +// "%c", 32 -> " " +// "%s", "C" -> "C" // "%s", TString("C++") -> "C++" -// "%d", -10 -> "-10" -// "%o", 10 -> "12" -// "%x", 16 -> "10" -// "%f", 123456789 -> "123456789.000000" -// "%e", .01 -> "1.00000e-2" -// "%a", -3.0 -> "-0x1.8p+1" -// "%g", .01 -> "1e-2" -// "%p", (void*)&value -> "0x7ffdeb6ad2a4" -// -// int n = 0; +// "%d", -10 -> "-10" +// "%o", 10 -> "12" +// "%x", 16 -> "10" +// "%f", 123456789 -> "123456789.000000" +// "%e", .01 -> "1.00000e-2" +// "%a", -3.0 -> "-0x1.8p+1" +// "%g", .01 -> "1e-2" +// "%p", (void*)&value -> "0x7ffdeb6ad2a4" +// +// int n = 0; // TString s = y_absl::StrFormat( // "%s%d%n", "hello", 123, y_absl::FormatCountCapture(&n)); -// EXPECT_EQ(8, n); -// -// The `FormatSpec` intrinsically supports all of these fundamental C++ types: -// -// * Characters: `char`, `signed char`, `unsigned char` -// * Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`, -// `unsigned long`, `long long`, `unsigned long long` -// * Floating-point: `float`, `double`, `long double` -// -// However, in the `str_format` library, a format conversion specifies a broader -// C++ conceptual category instead of an exact type. For example, `%s` binds to +// EXPECT_EQ(8, n); +// +// The `FormatSpec` intrinsically supports all of these fundamental C++ types: +// +// * Characters: `char`, `signed char`, `unsigned char` +// * Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`, +// `unsigned long`, `long long`, `unsigned long long` +// * Floating-point: `float`, `double`, `long double` +// +// However, in the `str_format` library, a format conversion specifies a broader +// C++ conceptual category instead of an exact type. For example, `%s` binds to // any string-like argument, so `TString`, `y_absl::string_view`, and -// `const char*` are all accepted. Likewise, `%d` accepts any integer-like -// argument, etc. - -template <typename... Args> +// `const char*` are all accepted. Likewise, `%d` accepts any integer-like +// argument, etc. + +template <typename... Args> using FormatSpec = str_format_internal::FormatSpecTemplate< str_format_internal::ArgumentToConv<Args>()...>; - -// ParsedFormat -// -// A `ParsedFormat` is a class template representing a preparsed `FormatSpec`, -// with template arguments specifying the conversion characters used within the -// format string. Such characters must be valid format type specifiers, and -// these type specifiers are checked at compile-time. -// -// Instances of `ParsedFormat` can be created, copied, and reused to speed up -// formatting loops. A `ParsedFormat` may either be constructed statically, or -// dynamically through its `New()` factory function, which only constructs a -// runtime object if the format is valid at that time. -// -// Example: -// -// // Verified at compile time. + +// ParsedFormat +// +// A `ParsedFormat` is a class template representing a preparsed `FormatSpec`, +// with template arguments specifying the conversion characters used within the +// format string. Such characters must be valid format type specifiers, and +// these type specifiers are checked at compile-time. +// +// Instances of `ParsedFormat` can be created, copied, and reused to speed up +// formatting loops. A `ParsedFormat` may either be constructed statically, or +// dynamically through its `New()` factory function, which only constructs a +// runtime object if the format is valid at that time. +// +// Example: +// +// // Verified at compile time. // y_absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!"); // y_absl::StrFormat(formatString, "TheVillage", 6); -// -// // Verified at runtime. +// +// // Verified at runtime. // auto format_runtime = y_absl::ParsedFormat<'d'>::New(format_string); -// if (format_runtime) { +// if (format_runtime) { // value = y_absl::StrFormat(*format_runtime, i); -// } else { -// ... error case ... -// } +// } else { +// ... error case ... +// } #if defined(__cpp_nontype_template_parameter_auto) // If C++17 is available, an 'extended' format is also allowed that can specify @@ -307,156 +307,156 @@ template <auto... Conv> using ParsedFormat = y_absl::str_format_internal::ExtendedParsedFormat< y_absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; #else -template <char... Conv> -using ParsedFormat = str_format_internal::ExtendedParsedFormat< +template <char... Conv> +using ParsedFormat = str_format_internal::ExtendedParsedFormat< y_absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; #endif // defined(__cpp_nontype_template_parameter_auto) - -// StrFormat() -// -// Returns a `string` given a `printf()`-style format string and zero or more -// additional arguments. Use it as you would `sprintf()`. `StrFormat()` is the -// primary formatting function within the `str_format` library, and should be -// used in most cases where you need type-safe conversion of types into -// formatted strings. -// -// The format string generally consists of ordinary character data along with -// one or more format conversion specifiers (denoted by the `%` character). -// Ordinary character data is returned unchanged into the result string, while -// each conversion specification performs a type substitution from -// `StrFormat()`'s other arguments. See the comments for `FormatSpec` for full -// information on the makeup of this format string. -// -// Example: -// + +// StrFormat() +// +// Returns a `string` given a `printf()`-style format string and zero or more +// additional arguments. Use it as you would `sprintf()`. `StrFormat()` is the +// primary formatting function within the `str_format` library, and should be +// used in most cases where you need type-safe conversion of types into +// formatted strings. +// +// The format string generally consists of ordinary character data along with +// one or more format conversion specifiers (denoted by the `%` character). +// Ordinary character data is returned unchanged into the result string, while +// each conversion specification performs a type substitution from +// `StrFormat()`'s other arguments. See the comments for `FormatSpec` for full +// information on the makeup of this format string. +// +// Example: +// // TString s = y_absl::StrFormat( -// "Welcome to %s, Number %d!", "The Village", 6); -// EXPECT_EQ("Welcome to The Village, Number 6!", s); -// -// Returns an empty string in case of error. -template <typename... Args> +// "Welcome to %s, Number %d!", "The Village", 6); +// EXPECT_EQ("Welcome to The Village, Number 6!", s); +// +// Returns an empty string in case of error. +template <typename... Args> ABSL_MUST_USE_RESULT TString StrFormat(const FormatSpec<Args...>& format, - const Args&... args) { - return str_format_internal::FormatPack( - str_format_internal::UntypedFormatSpecImpl::Extract(format), - {str_format_internal::FormatArgImpl(args)...}); -} - -// StrAppendFormat() -// -// Appends to a `dst` string given a format string, and zero or more additional -// arguments, returning `*dst` as a convenience for chaining purposes. Appends -// nothing in case of error (but possibly alters its capacity). -// -// Example: -// + const Args&... args) { + return str_format_internal::FormatPack( + str_format_internal::UntypedFormatSpecImpl::Extract(format), + {str_format_internal::FormatArgImpl(args)...}); +} + +// StrAppendFormat() +// +// Appends to a `dst` string given a format string, and zero or more additional +// arguments, returning `*dst` as a convenience for chaining purposes. Appends +// nothing in case of error (but possibly alters its capacity). +// +// Example: +// // TString orig("For example PI is approximately "); -// std::cout << StrAppendFormat(&orig, "%12.6f", 3.14); -template <typename... Args> +// std::cout << StrAppendFormat(&orig, "%12.6f", 3.14); +template <typename... Args> TString& StrAppendFormat(TString* dst, - const FormatSpec<Args...>& format, - const Args&... args) { - return str_format_internal::AppendPack( - dst, str_format_internal::UntypedFormatSpecImpl::Extract(format), - {str_format_internal::FormatArgImpl(args)...}); -} - -// StreamFormat() -// -// Writes to an output stream given a format string and zero or more arguments, -// generally in a manner that is more efficient than streaming the result of + const FormatSpec<Args...>& format, + const Args&... args) { + return str_format_internal::AppendPack( + dst, str_format_internal::UntypedFormatSpecImpl::Extract(format), + {str_format_internal::FormatArgImpl(args)...}); +} + +// StreamFormat() +// +// Writes to an output stream given a format string and zero or more arguments, +// generally in a manner that is more efficient than streaming the result of // `y_absl:: StrFormat()`. The returned object must be streamed before the full -// expression ends. -// -// Example: -// -// std::cout << StreamFormat("%12.6f", 3.14); -template <typename... Args> -ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat( - const FormatSpec<Args...>& format, const Args&... args) { - return str_format_internal::Streamable( - str_format_internal::UntypedFormatSpecImpl::Extract(format), - {str_format_internal::FormatArgImpl(args)...}); -} - -// PrintF() -// -// Writes to stdout given a format string and zero or more arguments. This -// function is functionally equivalent to `std::printf()` (and type-safe); +// expression ends. +// +// Example: +// +// std::cout << StreamFormat("%12.6f", 3.14); +template <typename... Args> +ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat( + const FormatSpec<Args...>& format, const Args&... args) { + return str_format_internal::Streamable( + str_format_internal::UntypedFormatSpecImpl::Extract(format), + {str_format_internal::FormatArgImpl(args)...}); +} + +// PrintF() +// +// Writes to stdout given a format string and zero or more arguments. This +// function is functionally equivalent to `std::printf()` (and type-safe); // prefer `y_absl::PrintF()` over `std::printf()`. -// -// Example: -// -// std::string_view s = "Ulaanbaatar"; +// +// Example: +// +// std::string_view s = "Ulaanbaatar"; // y_absl::PrintF("The capital of Mongolia is %s", s); -// -// Outputs: "The capital of Mongolia is Ulaanbaatar" -// -template <typename... Args> -int PrintF(const FormatSpec<Args...>& format, const Args&... args) { - return str_format_internal::FprintF( - stdout, str_format_internal::UntypedFormatSpecImpl::Extract(format), - {str_format_internal::FormatArgImpl(args)...}); -} - -// FPrintF() -// -// Writes to a file given a format string and zero or more arguments. This -// function is functionally equivalent to `std::fprintf()` (and type-safe); +// +// Outputs: "The capital of Mongolia is Ulaanbaatar" +// +template <typename... Args> +int PrintF(const FormatSpec<Args...>& format, const Args&... args) { + return str_format_internal::FprintF( + stdout, str_format_internal::UntypedFormatSpecImpl::Extract(format), + {str_format_internal::FormatArgImpl(args)...}); +} + +// FPrintF() +// +// Writes to a file given a format string and zero or more arguments. This +// function is functionally equivalent to `std::fprintf()` (and type-safe); // prefer `y_absl::FPrintF()` over `std::fprintf()`. -// -// Example: -// -// std::string_view s = "Ulaanbaatar"; +// +// Example: +// +// std::string_view s = "Ulaanbaatar"; // y_absl::FPrintF(stdout, "The capital of Mongolia is %s", s); -// -// Outputs: "The capital of Mongolia is Ulaanbaatar" -// -template <typename... Args> -int FPrintF(std::FILE* output, const FormatSpec<Args...>& format, - const Args&... args) { - return str_format_internal::FprintF( - output, str_format_internal::UntypedFormatSpecImpl::Extract(format), - {str_format_internal::FormatArgImpl(args)...}); -} - -// SNPrintF() -// -// Writes to a sized buffer given a format string and zero or more arguments. -// This function is functionally equivalent to `std::snprintf()` (and +// +// Outputs: "The capital of Mongolia is Ulaanbaatar" +// +template <typename... Args> +int FPrintF(std::FILE* output, const FormatSpec<Args...>& format, + const Args&... args) { + return str_format_internal::FprintF( + output, str_format_internal::UntypedFormatSpecImpl::Extract(format), + {str_format_internal::FormatArgImpl(args)...}); +} + +// SNPrintF() +// +// Writes to a sized buffer given a format string and zero or more arguments. +// This function is functionally equivalent to `std::snprintf()` (and // type-safe); prefer `y_absl::SNPrintF()` over `std::snprintf()`. -// +// // In particular, a successful call to `y_absl::SNPrintF()` writes at most `size` // bytes of the formatted output to `output`, including a NUL-terminator, and -// returns the number of bytes that would have been written if truncation did -// not occur. In the event of an error, a negative value is returned and `errno` -// is set. -// -// Example: -// -// std::string_view s = "Ulaanbaatar"; -// char output[128]; +// returns the number of bytes that would have been written if truncation did +// not occur. In the event of an error, a negative value is returned and `errno` +// is set. +// +// Example: +// +// std::string_view s = "Ulaanbaatar"; +// char output[128]; // y_absl::SNPrintF(output, sizeof(output), -// "The capital of Mongolia is %s", s); -// -// Post-condition: output == "The capital of Mongolia is Ulaanbaatar" -// -template <typename... Args> -int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format, - const Args&... args) { - return str_format_internal::SnprintF( - output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format), - {str_format_internal::FormatArgImpl(args)...}); -} - -// ----------------------------------------------------------------------------- -// Custom Output Formatting Functions -// ----------------------------------------------------------------------------- - -// FormatRawSink -// -// FormatRawSink is a type erased wrapper around arbitrary sink objects -// specifically used as an argument to `Format()`. +// "The capital of Mongolia is %s", s); +// +// Post-condition: output == "The capital of Mongolia is Ulaanbaatar" +// +template <typename... Args> +int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format, + const Args&... args) { + return str_format_internal::SnprintF( + output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format), + {str_format_internal::FormatArgImpl(args)...}); +} + +// ----------------------------------------------------------------------------- +// Custom Output Formatting Functions +// ----------------------------------------------------------------------------- + +// FormatRawSink +// +// FormatRawSink is a type erased wrapper around arbitrary sink objects +// specifically used as an argument to `Format()`. // // All the object has to do define an overload of `AbslFormatFlush()` for the // sink, usually by adding a ADL-based free function in the same namespace as @@ -467,105 +467,105 @@ int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format, // where `dest` is the pointer passed to `y_absl::Format()`. The function should // append `part` to `dest`. // -// FormatRawSink does not own the passed sink object. The passed object must -// outlive the FormatRawSink. -class FormatRawSink { - public: - // Implicitly convert from any type that provides the hook function as - // described above. - template <typename T, - typename = typename std::enable_if<std::is_constructible< - str_format_internal::FormatRawSinkImpl, T*>::value>::type> - FormatRawSink(T* raw) // NOLINT - : sink_(raw) {} - - private: - friend str_format_internal::FormatRawSinkImpl; - str_format_internal::FormatRawSinkImpl sink_; -}; - -// Format() -// -// Writes a formatted string to an arbitrary sink object (implementing the +// FormatRawSink does not own the passed sink object. The passed object must +// outlive the FormatRawSink. +class FormatRawSink { + public: + // Implicitly convert from any type that provides the hook function as + // described above. + template <typename T, + typename = typename std::enable_if<std::is_constructible< + str_format_internal::FormatRawSinkImpl, T*>::value>::type> + FormatRawSink(T* raw) // NOLINT + : sink_(raw) {} + + private: + friend str_format_internal::FormatRawSinkImpl; + str_format_internal::FormatRawSinkImpl sink_; +}; + +// Format() +// +// Writes a formatted string to an arbitrary sink object (implementing the // `y_absl::FormatRawSink` interface), using a format string and zero or more -// additional arguments. -// +// additional arguments. +// // By default, `TString`, `std::ostream`, and `y_absl::Cord` are supported as // destination objects. If a `TString` is used the formatted string is // appended to it. -// +// // `y_absl::Format()` is a generic version of `y_absl::StrAppendFormat()`, for // custom sinks. The format string, like format strings for `StrFormat()`, is // checked at compile-time. -// -// On failure, this function returns `false` and the state of the sink is -// unspecified. -template <typename... Args> -bool Format(FormatRawSink raw_sink, const FormatSpec<Args...>& format, - const Args&... args) { - return str_format_internal::FormatUntyped( - str_format_internal::FormatRawSinkImpl::Extract(raw_sink), - str_format_internal::UntypedFormatSpecImpl::Extract(format), - {str_format_internal::FormatArgImpl(args)...}); -} - -// FormatArg -// -// A type-erased handle to a format argument specifically used as an argument to -// `FormatUntyped()`. You may construct `FormatArg` by passing -// reference-to-const of any printable type. `FormatArg` is both copyable and -// assignable. The source data must outlive the `FormatArg` instance. See -// example below. -// -using FormatArg = str_format_internal::FormatArgImpl; - -// FormatUntyped() -// -// Writes a formatted string to an arbitrary sink object (implementing the +// +// On failure, this function returns `false` and the state of the sink is +// unspecified. +template <typename... Args> +bool Format(FormatRawSink raw_sink, const FormatSpec<Args...>& format, + const Args&... args) { + return str_format_internal::FormatUntyped( + str_format_internal::FormatRawSinkImpl::Extract(raw_sink), + str_format_internal::UntypedFormatSpecImpl::Extract(format), + {str_format_internal::FormatArgImpl(args)...}); +} + +// FormatArg +// +// A type-erased handle to a format argument specifically used as an argument to +// `FormatUntyped()`. You may construct `FormatArg` by passing +// reference-to-const of any printable type. `FormatArg` is both copyable and +// assignable. The source data must outlive the `FormatArg` instance. See +// example below. +// +using FormatArg = str_format_internal::FormatArgImpl; + +// FormatUntyped() +// +// Writes a formatted string to an arbitrary sink object (implementing the // `y_absl::FormatRawSink` interface), using an `UntypedFormatSpec` and zero or -// more additional arguments. -// -// This function acts as the most generic formatting function in the -// `str_format` library. The caller provides a raw sink, an unchecked format -// string, and (usually) a runtime specified list of arguments; no compile-time -// checking of formatting is performed within this function. As a result, a -// caller should check the return value to verify that no error occurred. -// On failure, this function returns `false` and the state of the sink is -// unspecified. -// +// more additional arguments. +// +// This function acts as the most generic formatting function in the +// `str_format` library. The caller provides a raw sink, an unchecked format +// string, and (usually) a runtime specified list of arguments; no compile-time +// checking of formatting is performed within this function. As a result, a +// caller should check the return value to verify that no error occurred. +// On failure, this function returns `false` and the state of the sink is +// unspecified. +// // The arguments are provided in an `y_absl::Span<const y_absl::FormatArg>`. // Each `y_absl::FormatArg` object binds to a single argument and keeps a -// reference to it. The values used to create the `FormatArg` objects must +// reference to it. The values used to create the `FormatArg` objects must // outlive this function call. -// -// Example: -// +// +// Example: +// // std::optional<TString> FormatDynamic( // const TString& in_format, // const vector<TString>& in_args) { // TString out; // std::vector<y_absl::FormatArg> args; -// for (const auto& v : in_args) { -// // It is important that 'v' is a reference to the objects in in_args. -// // The values we pass to FormatArg must outlive the call to -// // FormatUntyped. -// args.emplace_back(v); -// } +// for (const auto& v : in_args) { +// // It is important that 'v' is a reference to the objects in in_args. +// // The values we pass to FormatArg must outlive the call to +// // FormatUntyped. +// args.emplace_back(v); +// } // y_absl::UntypedFormatSpec format(in_format); // if (!y_absl::FormatUntyped(&out, format, args)) { -// return std::nullopt; -// } -// return std::move(out); -// } -// -ABSL_MUST_USE_RESULT inline bool FormatUntyped( - FormatRawSink raw_sink, const UntypedFormatSpec& format, +// return std::nullopt; +// } +// return std::move(out); +// } +// +ABSL_MUST_USE_RESULT inline bool FormatUntyped( + FormatRawSink raw_sink, const UntypedFormatSpec& format, y_absl::Span<const FormatArg> args) { - return str_format_internal::FormatUntyped( - str_format_internal::FormatRawSinkImpl::Extract(raw_sink), - str_format_internal::UntypedFormatSpecImpl::Extract(format), args); -} - + return str_format_internal::FormatUntyped( + str_format_internal::FormatRawSinkImpl::Extract(raw_sink), + str_format_internal::UntypedFormatSpecImpl::Extract(format), args); +} + //------------------------------------------------------------------------------ // StrFormat Extensions //------------------------------------------------------------------------------ @@ -808,5 +808,5 @@ struct FormatConvertResult { ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_STR_FORMAT_H_ + +#endif // ABSL_STRINGS_STR_FORMAT_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_join.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_join.h index 46a0323c6e..08a86c3383 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_join.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_join.h @@ -1,293 +1,293 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: str_join.h -// ----------------------------------------------------------------------------- -// -// This header file contains functions for joining a range of elements and +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: str_join.h +// ----------------------------------------------------------------------------- +// +// This header file contains functions for joining a range of elements and // returning the result as a TString. StrJoin operations are specified by -// passing a range, a separator string to use between the elements joined, and -// an optional Formatter responsible for converting each argument in the range -// to a string. If omitted, a default `AlphaNumFormatter()` is called on the +// passing a range, a separator string to use between the elements joined, and +// an optional Formatter responsible for converting each argument in the range +// to a string. If omitted, a default `AlphaNumFormatter()` is called on the // elements to be joined, using the same formatting that `y_absl::StrCat()` uses. -// This package defines a number of default formatters, and you can define your -// own implementations. -// -// Ranges are specified by passing a container with `std::begin()` and -// `std::end()` iterators, container-specific `begin()` and `end()` iterators, a -// brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous +// This package defines a number of default formatters, and you can define your +// own implementations. +// +// Ranges are specified by passing a container with `std::begin()` and +// `std::end()` iterators, container-specific `begin()` and `end()` iterators, a +// brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous // objects. The separator string is specified as an `y_absl::string_view`. -// +// // Because the default formatter uses the `y_absl::AlphaNum` class, // `y_absl::StrJoin()`, like `y_absl::StrCat()`, will work out-of-the-box on -// collections of strings, ints, floats, doubles, etc. -// -// Example: -// +// collections of strings, ints, floats, doubles, etc. +// +// Example: +// // std::vector<TString> v = {"foo", "bar", "baz"}; // TString s = y_absl::StrJoin(v, "-"); -// EXPECT_EQ("foo-bar-baz", s); -// +// EXPECT_EQ("foo-bar-baz", s); +// // See comments on the `y_absl::StrJoin()` function for more examples. - -#ifndef ABSL_STRINGS_STR_JOIN_H_ -#define ABSL_STRINGS_STR_JOIN_H_ - -#include <cstdio> -#include <cstring> -#include <initializer_list> -#include <iterator> + +#ifndef ABSL_STRINGS_STR_JOIN_H_ +#define ABSL_STRINGS_STR_JOIN_H_ + +#include <cstdio> +#include <cstring> +#include <initializer_list> +#include <iterator> #include <util/generic/string.h> -#include <tuple> -#include <type_traits> -#include <utility> - +#include <tuple> +#include <type_traits> +#include <utility> + #include "y_absl/base/macros.h" #include "y_absl/strings/internal/str_join_internal.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -// ----------------------------------------------------------------------------- -// Concept: Formatter -// ----------------------------------------------------------------------------- -// -// A Formatter is a function object that is responsible for formatting its + +// ----------------------------------------------------------------------------- +// Concept: Formatter +// ----------------------------------------------------------------------------- +// +// A Formatter is a function object that is responsible for formatting its // argument as a string and appending it to a given output TString. -// Formatters may be implemented as function objects, lambdas, or normal +// Formatters may be implemented as function objects, lambdas, or normal // functions. You may provide your own Formatter to enable `y_absl::StrJoin()` to -// work with arbitrary types. -// -// The following is an example of a custom Formatter that simply uses +// work with arbitrary types. +// +// The following is an example of a custom Formatter that simply uses // `std::to_string()` to format an integer as a TString. -// -// struct MyFormatter { +// +// struct MyFormatter { // void operator()(TString* out, int i) const { -// out->append(std::to_string(i)); -// } -// }; -// -// You would use the above formatter by passing an instance of it as the final +// out->append(std::to_string(i)); +// } +// }; +// +// You would use the above formatter by passing an instance of it as the final // argument to `y_absl::StrJoin()`: -// -// std::vector<int> v = {1, 2, 3, 4}; +// +// std::vector<int> v = {1, 2, 3, 4}; // TString s = y_absl::StrJoin(v, "-", MyFormatter()); -// EXPECT_EQ("1-2-3-4", s); -// -// The following standard formatters are provided within this file: -// -// - `AlphaNumFormatter()` (the default) -// - `StreamFormatter()` -// - `PairFormatter()` -// - `DereferenceFormatter()` - -// AlphaNumFormatter() -// +// EXPECT_EQ("1-2-3-4", s); +// +// The following standard formatters are provided within this file: +// +// - `AlphaNumFormatter()` (the default) +// - `StreamFormatter()` +// - `PairFormatter()` +// - `DereferenceFormatter()` + +// AlphaNumFormatter() +// // Default formatter used if none is specified. Uses `y_absl::AlphaNum` to convert -// numeric arguments to strings. -inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() { - return strings_internal::AlphaNumFormatterImpl(); -} - -// StreamFormatter() -// -// Formats its argument using the << operator. -inline strings_internal::StreamFormatterImpl StreamFormatter() { - return strings_internal::StreamFormatterImpl(); -} - +// numeric arguments to strings. +inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() { + return strings_internal::AlphaNumFormatterImpl(); +} + +// StreamFormatter() +// +// Formats its argument using the << operator. +inline strings_internal::StreamFormatterImpl StreamFormatter() { + return strings_internal::StreamFormatterImpl(); +} + // Function Template: PairFormatter(Formatter, y_absl::string_view, Formatter) -// -// Formats a `std::pair` by putting a given separator between the pair's -// `.first` and `.second` members. This formatter allows you to specify -// custom Formatters for both the first and second member of each pair. -template <typename FirstFormatter, typename SecondFormatter> -inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter> +// +// Formats a `std::pair` by putting a given separator between the pair's +// `.first` and `.second` members. This formatter allows you to specify +// custom Formatters for both the first and second member of each pair. +template <typename FirstFormatter, typename SecondFormatter> +inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter> PairFormatter(FirstFormatter f1, y_absl::string_view sep, SecondFormatter f2) { - return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>( - std::move(f1), sep, std::move(f2)); -} - -// Function overload of PairFormatter() for using a default -// `AlphaNumFormatter()` for each Formatter in the pair. -inline strings_internal::PairFormatterImpl< - strings_internal::AlphaNumFormatterImpl, - strings_internal::AlphaNumFormatterImpl> + return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>( + std::move(f1), sep, std::move(f2)); +} + +// Function overload of PairFormatter() for using a default +// `AlphaNumFormatter()` for each Formatter in the pair. +inline strings_internal::PairFormatterImpl< + strings_internal::AlphaNumFormatterImpl, + strings_internal::AlphaNumFormatterImpl> PairFormatter(y_absl::string_view sep) { - return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter()); -} - -// Function Template: DereferenceFormatter(Formatter) -// -// Formats its argument by dereferencing it and then applying the given -// formatter. This formatter is useful for formatting a container of -// pointer-to-T. This pattern often shows up when joining repeated fields in -// protocol buffers. -template <typename Formatter> -strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter( - Formatter&& f) { - return strings_internal::DereferenceFormatterImpl<Formatter>( - std::forward<Formatter>(f)); -} - + return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter()); +} + +// Function Template: DereferenceFormatter(Formatter) +// +// Formats its argument by dereferencing it and then applying the given +// formatter. This formatter is useful for formatting a container of +// pointer-to-T. This pattern often shows up when joining repeated fields in +// protocol buffers. +template <typename Formatter> +strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter( + Formatter&& f) { + return strings_internal::DereferenceFormatterImpl<Formatter>( + std::forward<Formatter>(f)); +} + // Function overload of `DereferenceFormatter()` for using a default -// `AlphaNumFormatter()`. -inline strings_internal::DereferenceFormatterImpl< - strings_internal::AlphaNumFormatterImpl> -DereferenceFormatter() { - return strings_internal::DereferenceFormatterImpl< - strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter()); -} - -// ----------------------------------------------------------------------------- -// StrJoin() -// ----------------------------------------------------------------------------- -// +// `AlphaNumFormatter()`. +inline strings_internal::DereferenceFormatterImpl< + strings_internal::AlphaNumFormatterImpl> +DereferenceFormatter() { + return strings_internal::DereferenceFormatterImpl< + strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter()); +} + +// ----------------------------------------------------------------------------- +// StrJoin() +// ----------------------------------------------------------------------------- +// // Joins a range of elements and returns the result as a TString. // `y_absl::StrJoin()` takes a range, a separator string to use between the -// elements joined, and an optional Formatter responsible for converting each -// argument in the range to a string. -// -// If omitted, the default `AlphaNumFormatter()` is called on the elements to be -// joined. -// -// Example 1: -// // Joins a collection of strings. This pattern also works with a collection +// elements joined, and an optional Formatter responsible for converting each +// argument in the range to a string. +// +// If omitted, the default `AlphaNumFormatter()` is called on the elements to be +// joined. +// +// Example 1: +// // Joins a collection of strings. This pattern also works with a collection // // of `y_absl::string_view` or even `const char*`. // std::vector<TString> v = {"foo", "bar", "baz"}; // TString s = y_absl::StrJoin(v, "-"); -// EXPECT_EQ("foo-bar-baz", s); -// -// Example 2: -// // Joins the values in the given `std::initializer_list<>` specified using -// // brace initialization. This pattern also works with an initializer_list +// EXPECT_EQ("foo-bar-baz", s); +// +// Example 2: +// // Joins the values in the given `std::initializer_list<>` specified using +// // brace initialization. This pattern also works with an initializer_list // // of ints or `y_absl::string_view` -- any `AlphaNum`-compatible type. // TString s = y_absl::StrJoin({"foo", "bar", "baz"}, "-"); -// EXPECT_EQ("foo-bar-baz", s); -// -// Example 3: -// // Joins a collection of ints. This pattern also works with floats, -// // doubles, int64s -- any `StrCat()`-compatible type. -// std::vector<int> v = {1, 2, 3, -4}; +// EXPECT_EQ("foo-bar-baz", s); +// +// Example 3: +// // Joins a collection of ints. This pattern also works with floats, +// // doubles, int64s -- any `StrCat()`-compatible type. +// std::vector<int> v = {1, 2, 3, -4}; // TString s = y_absl::StrJoin(v, "-"); -// EXPECT_EQ("1-2-3--4", s); -// -// Example 4: -// // Joins a collection of pointer-to-int. By default, pointers are -// // dereferenced and the pointee is formatted using the default format for -// // that type; such dereferencing occurs for all levels of indirection, so -// // this pattern works just as well for `std::vector<int**>` as for -// // `std::vector<int*>`. -// int x = 1, y = 2, z = 3; -// std::vector<int*> v = {&x, &y, &z}; +// EXPECT_EQ("1-2-3--4", s); +// +// Example 4: +// // Joins a collection of pointer-to-int. By default, pointers are +// // dereferenced and the pointee is formatted using the default format for +// // that type; such dereferencing occurs for all levels of indirection, so +// // this pattern works just as well for `std::vector<int**>` as for +// // `std::vector<int*>`. +// int x = 1, y = 2, z = 3; +// std::vector<int*> v = {&x, &y, &z}; // TString s = y_absl::StrJoin(v, "-"); -// EXPECT_EQ("1-2-3", s); -// -// Example 5: -// // Dereferencing of `std::unique_ptr<>` is also supported: -// std::vector<std::unique_ptr<int>> v -// v.emplace_back(new int(1)); -// v.emplace_back(new int(2)); -// v.emplace_back(new int(3)); +// EXPECT_EQ("1-2-3", s); +// +// Example 5: +// // Dereferencing of `std::unique_ptr<>` is also supported: +// std::vector<std::unique_ptr<int>> v +// v.emplace_back(new int(1)); +// v.emplace_back(new int(2)); +// v.emplace_back(new int(3)); // TString s = y_absl::StrJoin(v, "-"); -// EXPECT_EQ("1-2-3", s); -// -// Example 6: -// // Joins a `std::map`, with each key-value pair separated by an equals -// // sign. This pattern would also work with, say, a -// // `std::vector<std::pair<>>`. +// EXPECT_EQ("1-2-3", s); +// +// Example 6: +// // Joins a `std::map`, with each key-value pair separated by an equals +// // sign. This pattern would also work with, say, a +// // `std::vector<std::pair<>>`. // std::map<TString, int> m = { -// std::make_pair("a", 1), -// std::make_pair("b", 2), -// std::make_pair("c", 3)}; +// std::make_pair("a", 1), +// std::make_pair("b", 2), +// std::make_pair("c", 3)}; // TString s = y_absl::StrJoin(m, ",", y_absl::PairFormatter("=")); -// EXPECT_EQ("a=1,b=2,c=3", s); -// -// Example 7: +// EXPECT_EQ("a=1,b=2,c=3", s); +// +// Example 7: // // These examples show how `y_absl::StrJoin()` handles a few common edge -// // cases: +// // cases: // std::vector<TString> v_empty; // EXPECT_EQ("", y_absl::StrJoin(v_empty, "-")); -// +// // std::vector<TString> v_one_item = {"foo"}; // EXPECT_EQ("foo", y_absl::StrJoin(v_one_item, "-")); -// +// // std::vector<TString> v_empty_string = {""}; // EXPECT_EQ("", y_absl::StrJoin(v_empty_string, "-")); -// +// // std::vector<TString> v_one_item_empty_string = {"a", ""}; // EXPECT_EQ("a-", y_absl::StrJoin(v_one_item_empty_string, "-")); -// +// // std::vector<TString> v_two_empty_string = {"", ""}; // EXPECT_EQ("-", y_absl::StrJoin(v_two_empty_string, "-")); -// -// Example 8: -// // Joins a `std::tuple<T...>` of heterogeneous types, converting each to +// +// Example 8: +// // Joins a `std::tuple<T...>` of heterogeneous types, converting each to // // a TString using the `y_absl::AlphaNum` class. // TString s = y_absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); -// EXPECT_EQ("123-abc-0.456", s); - -template <typename Iterator, typename Formatter> +// EXPECT_EQ("123-abc-0.456", s); + +template <typename Iterator, typename Formatter> TString StrJoin(Iterator start, Iterator end, y_absl::string_view sep, - Formatter&& fmt) { - return strings_internal::JoinAlgorithm(start, end, sep, fmt); -} - -template <typename Range, typename Formatter> + Formatter&& fmt) { + return strings_internal::JoinAlgorithm(start, end, sep, fmt); +} + +template <typename Range, typename Formatter> TString StrJoin(const Range& range, y_absl::string_view separator, - Formatter&& fmt) { - return strings_internal::JoinRange(range, separator, fmt); -} - -template <typename T, typename Formatter> + Formatter&& fmt) { + return strings_internal::JoinRange(range, separator, fmt); +} + +template <typename T, typename Formatter> TString StrJoin(std::initializer_list<T> il, y_absl::string_view separator, - Formatter&& fmt) { - return strings_internal::JoinRange(il, separator, fmt); -} - -template <typename... T, typename Formatter> + Formatter&& fmt) { + return strings_internal::JoinRange(il, separator, fmt); +} + +template <typename... T, typename Formatter> TString StrJoin(const std::tuple<T...>& value, y_absl::string_view separator, - Formatter&& fmt) { - return strings_internal::JoinAlgorithm(value, separator, fmt); -} - -template <typename Iterator> + Formatter&& fmt) { + return strings_internal::JoinAlgorithm(value, separator, fmt); +} + +template <typename Iterator> TString StrJoin(Iterator start, Iterator end, y_absl::string_view separator) { - return strings_internal::JoinRange(start, end, separator); -} - -template <typename Range> + return strings_internal::JoinRange(start, end, separator); +} + +template <typename Range> TString StrJoin(const Range& range, y_absl::string_view separator) { - return strings_internal::JoinRange(range, separator); -} - -template <typename T> + return strings_internal::JoinRange(range, separator); +} + +template <typename T> TString StrJoin(std::initializer_list<T> il, y_absl::string_view separator) { - return strings_internal::JoinRange(il, separator); -} - -template <typename... T> + return strings_internal::JoinRange(il, separator); +} + +template <typename... T> TString StrJoin(const std::tuple<T...>& value, y_absl::string_view separator) { - return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter()); -} - + return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter()); +} + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_STR_JOIN_H_ + +#endif // ABSL_STRINGS_STR_JOIN_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_replace.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_replace.cc index 77b78c6c16..97ba70f9c4 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_replace.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_replace.cc @@ -1,82 +1,82 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/str_replace.h" - + #include "y_absl/strings/str_cat.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -using FixedMapping = +namespace strings_internal { + +using FixedMapping = std::initializer_list<std::pair<y_absl::string_view, y_absl::string_view>>; - + // Applies the ViableSubstitutions in subs_ptr to the y_absl::string_view s, and -// stores the result in *result_ptr. Returns the number of substitutions that -// occurred. -int ApplySubstitutions( +// stores the result in *result_ptr. Returns the number of substitutions that +// occurred. +int ApplySubstitutions( y_absl::string_view s, - std::vector<strings_internal::ViableSubstitution>* subs_ptr, + std::vector<strings_internal::ViableSubstitution>* subs_ptr, TString* result_ptr) { - auto& subs = *subs_ptr; - int substitutions = 0; - size_t pos = 0; - while (!subs.empty()) { - auto& sub = subs.back(); - if (sub.offset >= pos) { - if (pos <= s.size()) { - StrAppend(result_ptr, s.substr(pos, sub.offset - pos), sub.replacement); - } - pos = sub.offset + sub.old.size(); - substitutions += 1; - } - sub.offset = s.find(sub.old, pos); - if (sub.offset == s.npos) { - subs.pop_back(); - } else { - // Insertion sort to ensure the last ViableSubstitution continues to be - // before all the others. - size_t index = subs.size(); - while (--index && subs[index - 1].OccursBefore(subs[index])) { - std::swap(subs[index], subs[index - 1]); - } - } - } - result_ptr->append(s.data() + pos, s.size() - pos); - return substitutions; -} - -} // namespace strings_internal - -// We can implement this in terms of the generic StrReplaceAll, but -// we must specify the template overload because C++ cannot deduce the type -// of an initializer_list parameter to a function, and also if we don't specify -// the type, we just call ourselves. -// -// Note that we implement them here, rather than in the header, so that they -// aren't inlined. - + auto& subs = *subs_ptr; + int substitutions = 0; + size_t pos = 0; + while (!subs.empty()) { + auto& sub = subs.back(); + if (sub.offset >= pos) { + if (pos <= s.size()) { + StrAppend(result_ptr, s.substr(pos, sub.offset - pos), sub.replacement); + } + pos = sub.offset + sub.old.size(); + substitutions += 1; + } + sub.offset = s.find(sub.old, pos); + if (sub.offset == s.npos) { + subs.pop_back(); + } else { + // Insertion sort to ensure the last ViableSubstitution continues to be + // before all the others. + size_t index = subs.size(); + while (--index && subs[index - 1].OccursBefore(subs[index])) { + std::swap(subs[index], subs[index - 1]); + } + } + } + result_ptr->append(s.data() + pos, s.size() - pos); + return substitutions; +} + +} // namespace strings_internal + +// We can implement this in terms of the generic StrReplaceAll, but +// we must specify the template overload because C++ cannot deduce the type +// of an initializer_list parameter to a function, and also if we don't specify +// the type, we just call ourselves. +// +// Note that we implement them here, rather than in the header, so that they +// aren't inlined. + TString StrReplaceAll(y_absl::string_view s, - strings_internal::FixedMapping replacements) { - return StrReplaceAll<strings_internal::FixedMapping>(s, replacements); -} - -int StrReplaceAll(strings_internal::FixedMapping replacements, + strings_internal::FixedMapping replacements) { + return StrReplaceAll<strings_internal::FixedMapping>(s, replacements); +} + +int StrReplaceAll(strings_internal::FixedMapping replacements, TString* target) { - return StrReplaceAll<strings_internal::FixedMapping>(replacements, target); -} - + return StrReplaceAll<strings_internal::FixedMapping>(replacements, target); +} + ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_replace.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_replace.h index 42c85616a0..5c44e5dc64 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_replace.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_replace.h @@ -1,219 +1,219 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: str_replace.h -// ----------------------------------------------------------------------------- -// +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: str_replace.h +// ----------------------------------------------------------------------------- +// // This file defines `y_absl::StrReplaceAll()`, a general-purpose string -// replacement function designed for large, arbitrary text substitutions, -// especially on strings which you are receiving from some other system for -// further processing (e.g. processing regular expressions, escaping HTML -// entities, etc.). `StrReplaceAll` is designed to be efficient even when only -// one substitution is being performed, or when substitution is rare. -// -// If the string being modified is known at compile-time, and the substitutions +// replacement function designed for large, arbitrary text substitutions, +// especially on strings which you are receiving from some other system for +// further processing (e.g. processing regular expressions, escaping HTML +// entities, etc.). `StrReplaceAll` is designed to be efficient even when only +// one substitution is being performed, or when substitution is rare. +// +// If the string being modified is known at compile-time, and the substitutions // vary, `y_absl::Substitute()` may be a better choice. -// -// Example: -// +// +// Example: +// // TString html_escaped = y_absl::StrReplaceAll(user_input, { -// {"&", "&"}, -// {"<", "<"}, -// {">", ">"}, -// {"\"", """}, -// {"'", "'"}}); -#ifndef ABSL_STRINGS_STR_REPLACE_H_ -#define ABSL_STRINGS_STR_REPLACE_H_ - +// {"&", "&"}, +// {"<", "<"}, +// {">", ">"}, +// {"\"", """}, +// {"'", "'"}}); +#ifndef ABSL_STRINGS_STR_REPLACE_H_ +#define ABSL_STRINGS_STR_REPLACE_H_ + #include <util/generic/string.h> -#include <utility> -#include <vector> - +#include <utility> +#include <vector> + #include "y_absl/base/attributes.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -// StrReplaceAll() -// -// Replaces character sequences within a given string with replacements provided -// within an initializer list of key/value pairs. Candidate replacements are -// considered in order as they occur within the string, with earlier matches -// taking precedence, and longer matches taking precedence for candidates -// starting at the same position in the string. Once a substitution is made, the -// replaced text is not considered for any further substitutions. -// -// Example: -// + +// StrReplaceAll() +// +// Replaces character sequences within a given string with replacements provided +// within an initializer list of key/value pairs. Candidate replacements are +// considered in order as they occur within the string, with earlier matches +// taking precedence, and longer matches taking precedence for candidates +// starting at the same position in the string. Once a substitution is made, the +// replaced text is not considered for any further substitutions. +// +// Example: +// // TString s = y_absl::StrReplaceAll( -// "$who bought $count #Noun. Thanks $who!", +// "$who bought $count #Noun. Thanks $who!", // {{"$count", y_absl::StrCat(5)}, -// {"$who", "Bob"}, -// {"#Noun", "Apples"}}); -// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); +// {"$who", "Bob"}, +// {"#Noun", "Apples"}}); +// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); ABSL_MUST_USE_RESULT TString StrReplaceAll( y_absl::string_view s, std::initializer_list<std::pair<y_absl::string_view, y_absl::string_view>> - replacements); - -// Overload of `StrReplaceAll()` to accept a container of key/value replacement -// pairs (typically either an associative map or a `std::vector` of `std::pair` -// elements). A vector of pairs is generally more efficient. -// -// Examples: -// + replacements); + +// Overload of `StrReplaceAll()` to accept a container of key/value replacement +// pairs (typically either an associative map or a `std::vector` of `std::pair` +// elements). A vector of pairs is generally more efficient. +// +// Examples: +// // std::map<const y_absl::string_view, const y_absl::string_view> replacements; -// replacements["$who"] = "Bob"; -// replacements["$count"] = "5"; -// replacements["#Noun"] = "Apples"; +// replacements["$who"] = "Bob"; +// replacements["$count"] = "5"; +// replacements["#Noun"] = "Apples"; // TString s = y_absl::StrReplaceAll( -// "$who bought $count #Noun. Thanks $who!", -// replacements); -// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); -// -// // A std::vector of std::pair elements can be more efficient. +// "$who bought $count #Noun. Thanks $who!", +// replacements); +// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); +// +// // A std::vector of std::pair elements can be more efficient. // std::vector<std::pair<const y_absl::string_view, TString>> replacements; -// replacements.push_back({"&", "&"}); -// replacements.push_back({"<", "<"}); -// replacements.push_back({">", ">"}); +// replacements.push_back({"&", "&"}); +// replacements.push_back({"<", "<"}); +// replacements.push_back({">", ">"}); // TString s = y_absl::StrReplaceAll("if (ptr < &foo)", -// replacements); -// EXPECT_EQ("if (ptr < &foo)", s); -template <typename StrToStrMapping> +// replacements); +// EXPECT_EQ("if (ptr < &foo)", s); +template <typename StrToStrMapping> TString StrReplaceAll(y_absl::string_view s, - const StrToStrMapping& replacements); - -// Overload of `StrReplaceAll()` to replace character sequences within a given -// output string *in place* with replacements provided within an initializer -// list of key/value pairs, returning the number of substitutions that occurred. -// -// Example: -// + const StrToStrMapping& replacements); + +// Overload of `StrReplaceAll()` to replace character sequences within a given +// output string *in place* with replacements provided within an initializer +// list of key/value pairs, returning the number of substitutions that occurred. +// +// Example: +// // TString s = TString("$who bought $count #Noun. Thanks $who!"); -// int count; +// int count; // count = y_absl::StrReplaceAll({{"$count", y_absl::StrCat(5)}, -// {"$who", "Bob"}, -// {"#Noun", "Apples"}}, &s); -// EXPECT_EQ(count, 4); -// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); -int StrReplaceAll( +// {"$who", "Bob"}, +// {"#Noun", "Apples"}}, &s); +// EXPECT_EQ(count, 4); +// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); +int StrReplaceAll( std::initializer_list<std::pair<y_absl::string_view, y_absl::string_view>> - replacements, + replacements, TString* target); - -// Overload of `StrReplaceAll()` to replace patterns within a given output -// string *in place* with replacements provided within a container of key/value -// pairs. -// -// Example: -// + +// Overload of `StrReplaceAll()` to replace patterns within a given output +// string *in place* with replacements provided within a container of key/value +// pairs. +// +// Example: +// // TString s = TString("if (ptr < &foo)"); // int count = y_absl::StrReplaceAll({{"&", "&"}, -// {"<", "<"}, -// {">", ">"}}, &s); -// EXPECT_EQ(count, 2); -// EXPECT_EQ("if (ptr < &foo)", s); -template <typename StrToStrMapping> +// {"<", "<"}, +// {">", ">"}}, &s); +// EXPECT_EQ(count, 2); +// EXPECT_EQ("if (ptr < &foo)", s); +template <typename StrToStrMapping> int StrReplaceAll(const StrToStrMapping& replacements, TString* target); - -// Implementation details only, past this point. -namespace strings_internal { - -struct ViableSubstitution { + +// Implementation details only, past this point. +namespace strings_internal { + +struct ViableSubstitution { y_absl::string_view old; y_absl::string_view replacement; - size_t offset; - + size_t offset; + ViableSubstitution(y_absl::string_view old_str, y_absl::string_view replacement_str, size_t offset_val) - : old(old_str), replacement(replacement_str), offset(offset_val) {} - - // One substitution occurs "before" another (takes priority) if either - // it has the lowest offset, or it has the same offset but a larger size. - bool OccursBefore(const ViableSubstitution& y) const { - if (offset != y.offset) return offset < y.offset; - return old.size() > y.old.size(); - } -}; - -// Build a vector of ViableSubstitutions based on the given list of -// replacements. subs can be implemented as a priority_queue. However, it turns -// out that most callers have small enough a list of substitutions that the -// overhead of such a queue isn't worth it. -template <typename StrToStrMapping> -std::vector<ViableSubstitution> FindSubstitutions( + : old(old_str), replacement(replacement_str), offset(offset_val) {} + + // One substitution occurs "before" another (takes priority) if either + // it has the lowest offset, or it has the same offset but a larger size. + bool OccursBefore(const ViableSubstitution& y) const { + if (offset != y.offset) return offset < y.offset; + return old.size() > y.old.size(); + } +}; + +// Build a vector of ViableSubstitutions based on the given list of +// replacements. subs can be implemented as a priority_queue. However, it turns +// out that most callers have small enough a list of substitutions that the +// overhead of such a queue isn't worth it. +template <typename StrToStrMapping> +std::vector<ViableSubstitution> FindSubstitutions( y_absl::string_view s, const StrToStrMapping& replacements) { - std::vector<ViableSubstitution> subs; - subs.reserve(replacements.size()); - - for (const auto& rep : replacements) { - using std::get; + std::vector<ViableSubstitution> subs; + subs.reserve(replacements.size()); + + for (const auto& rep : replacements) { + using std::get; y_absl::string_view old(get<0>(rep)); - - size_t pos = s.find(old); - if (pos == s.npos) continue; - - // Ignore attempts to replace "". This condition is almost never true, - // but above condition is frequently true. That's why we test for this - // now and not before. - if (old.empty()) continue; - - subs.emplace_back(old, get<1>(rep), pos); - - // Insertion sort to ensure the last ViableSubstitution comes before - // all the others. - size_t index = subs.size(); - while (--index && subs[index - 1].OccursBefore(subs[index])) { - std::swap(subs[index], subs[index - 1]); - } - } - return subs; -} - + + size_t pos = s.find(old); + if (pos == s.npos) continue; + + // Ignore attempts to replace "". This condition is almost never true, + // but above condition is frequently true. That's why we test for this + // now and not before. + if (old.empty()) continue; + + subs.emplace_back(old, get<1>(rep), pos); + + // Insertion sort to ensure the last ViableSubstitution comes before + // all the others. + size_t index = subs.size(); + while (--index && subs[index - 1].OccursBefore(subs[index])) { + std::swap(subs[index], subs[index - 1]); + } + } + return subs; +} + int ApplySubstitutions(y_absl::string_view s, - std::vector<ViableSubstitution>* subs_ptr, + std::vector<ViableSubstitution>* subs_ptr, TString* result_ptr); - -} // namespace strings_internal - -template <typename StrToStrMapping> + +} // namespace strings_internal + +template <typename StrToStrMapping> TString StrReplaceAll(y_absl::string_view s, - const StrToStrMapping& replacements) { - auto subs = strings_internal::FindSubstitutions(s, replacements); + const StrToStrMapping& replacements) { + auto subs = strings_internal::FindSubstitutions(s, replacements); TString result; - result.reserve(s.size()); - strings_internal::ApplySubstitutions(s, &subs, &result); - return result; -} - -template <typename StrToStrMapping> + result.reserve(s.size()); + strings_internal::ApplySubstitutions(s, &subs, &result); + return result; +} + +template <typename StrToStrMapping> int StrReplaceAll(const StrToStrMapping& replacements, TString* target) { - auto subs = strings_internal::FindSubstitutions(*target, replacements); - if (subs.empty()) return 0; - + auto subs = strings_internal::FindSubstitutions(*target, replacements); + if (subs.empty()) return 0; + TString result; - result.reserve(target->size()); - int substitutions = - strings_internal::ApplySubstitutions(*target, &subs, &result); - target->swap(result); - return substitutions; -} - + result.reserve(target->size()); + int substitutions = + strings_internal::ApplySubstitutions(*target, &subs, &result); + target->swap(result); + return substitutions; +} + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_STR_REPLACE_H_ + +#endif // ABSL_STRINGS_STR_REPLACE_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.cc index 5f9193e6ba..0ddb54a86c 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.cc @@ -1,139 +1,139 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/str_split.h" - -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <cstdlib> -#include <cstring> -#include <iterator> -#include <limits> -#include <memory> - + +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <iterator> +#include <limits> +#include <memory> + #include "y_absl/base/internal/raw_logging.h" #include "y_absl/strings/ascii.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -namespace { - -// This GenericFind() template function encapsulates the finding algorithm -// shared between the ByString and ByAnyChar delimiters. The FindPolicy -// template parameter allows each delimiter to customize the actual find -// function to use and the length of the found delimiter. For example, the + +namespace { + +// This GenericFind() template function encapsulates the finding algorithm +// shared between the ByString and ByAnyChar delimiters. The FindPolicy +// template parameter allows each delimiter to customize the actual find +// function to use and the length of the found delimiter. For example, the // Literal delimiter will ultimately use y_absl::string_view::find(), and the // AnyOf delimiter will use y_absl::string_view::find_first_of(). -template <typename FindPolicy> +template <typename FindPolicy> y_absl::string_view GenericFind(y_absl::string_view text, y_absl::string_view delimiter, size_t pos, - FindPolicy find_policy) { - if (delimiter.empty() && text.length() > 0) { + FindPolicy find_policy) { + if (delimiter.empty() && text.length() > 0) { // Special case for empty string delimiters: always return a zero-length // y_absl::string_view referring to the item at position 1 past pos. return y_absl::string_view(text.data() + pos + 1, 0); - } + } size_t found_pos = y_absl::string_view::npos; y_absl::string_view found(text.data() + text.size(), - 0); // By default, not found - found_pos = find_policy.Find(text, delimiter, pos); + 0); // By default, not found + found_pos = find_policy.Find(text, delimiter, pos); if (found_pos != y_absl::string_view::npos) { found = y_absl::string_view(text.data() + found_pos, - find_policy.Length(delimiter)); - } - return found; -} - + find_policy.Length(delimiter)); + } + return found; +} + // Finds using y_absl::string_view::find(), therefore the length of the found -// delimiter is delimiter.length(). -struct LiteralPolicy { +// delimiter is delimiter.length(). +struct LiteralPolicy { size_t Find(y_absl::string_view text, y_absl::string_view delimiter, size_t pos) { - return text.find(delimiter, pos); - } + return text.find(delimiter, pos); + } size_t Length(y_absl::string_view delimiter) { return delimiter.length(); } -}; - +}; + // Finds using y_absl::string_view::find_first_of(), therefore the length of the -// found delimiter is 1. -struct AnyOfPolicy { +// found delimiter is 1. +struct AnyOfPolicy { size_t Find(y_absl::string_view text, y_absl::string_view delimiter, size_t pos) { - return text.find_first_of(delimiter, pos); - } + return text.find_first_of(delimiter, pos); + } size_t Length(y_absl::string_view /* delimiter */) { return 1; } -}; - -} // namespace - -// -// ByString -// - +}; + +} // namespace + +// +// ByString +// + ByString::ByString(y_absl::string_view sp) : delimiter_(sp) {} - + y_absl::string_view ByString::Find(y_absl::string_view text, size_t pos) const { - if (delimiter_.length() == 1) { - // Much faster to call find on a single character than on an + if (delimiter_.length() == 1) { + // Much faster to call find on a single character than on an // y_absl::string_view. - size_t found_pos = text.find(delimiter_[0], pos); + size_t found_pos = text.find(delimiter_[0], pos); if (found_pos == y_absl::string_view::npos) return y_absl::string_view(text.data() + text.size(), 0); - return text.substr(found_pos, 1); - } - return GenericFind(text, delimiter_, pos, LiteralPolicy()); -} - -// -// ByChar -// - + return text.substr(found_pos, 1); + } + return GenericFind(text, delimiter_, pos, LiteralPolicy()); +} + +// +// ByChar +// + y_absl::string_view ByChar::Find(y_absl::string_view text, size_t pos) const { - size_t found_pos = text.find(c_, pos); + size_t found_pos = text.find(c_, pos); if (found_pos == y_absl::string_view::npos) return y_absl::string_view(text.data() + text.size(), 0); - return text.substr(found_pos, 1); -} - -// -// ByAnyChar -// - + return text.substr(found_pos, 1); +} + +// +// ByAnyChar +// + ByAnyChar::ByAnyChar(y_absl::string_view sp) : delimiters_(sp) {} - + y_absl::string_view ByAnyChar::Find(y_absl::string_view text, size_t pos) const { - return GenericFind(text, delimiters_, pos, AnyOfPolicy()); -} - -// -// ByLength -// -ByLength::ByLength(ptrdiff_t length) : length_(length) { - ABSL_RAW_CHECK(length > 0, ""); -} - + return GenericFind(text, delimiters_, pos, AnyOfPolicy()); +} + +// +// ByLength +// +ByLength::ByLength(ptrdiff_t length) : length_(length) { + ABSL_RAW_CHECK(length > 0, ""); +} + y_absl::string_view ByLength::Find(y_absl::string_view text, - size_t pos) const { - pos = std::min(pos, text.size()); // truncate `pos` + size_t pos) const { + pos = std::min(pos, text.size()); // truncate `pos` y_absl::string_view substr = text.substr(pos); // If the string is shorter than the chunk size we say we - // "can't find the delimiter" so this will be the last chunk. - if (substr.length() <= static_cast<size_t>(length_)) + // "can't find the delimiter" so this will be the last chunk. + if (substr.length() <= static_cast<size_t>(length_)) return y_absl::string_view(text.data() + text.size(), 0); - + return y_absl::string_view(substr.data() + length_, 0); -} - +} + ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.h index d32d54813e..93ccc3d8f9 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.h @@ -1,505 +1,505 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: str_split.h -// ----------------------------------------------------------------------------- -// -// This file contains functions for splitting strings. It defines the main -// `StrSplit()` function, several delimiters for determining the boundaries on -// which to split the string, and predicates for filtering delimited results. -// `StrSplit()` adapts the returned collection to the type specified by the -// caller. -// -// Example: -// -// // Splits the given string on commas. Returns the results in a -// // vector of strings. +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: str_split.h +// ----------------------------------------------------------------------------- +// +// This file contains functions for splitting strings. It defines the main +// `StrSplit()` function, several delimiters for determining the boundaries on +// which to split the string, and predicates for filtering delimited results. +// `StrSplit()` adapts the returned collection to the type specified by the +// caller. +// +// Example: +// +// // Splits the given string on commas. Returns the results in a +// // vector of strings. // std::vector<TString> v = y_absl::StrSplit("a,b,c", ','); -// // Can also use "," -// // v[0] == "a", v[1] == "b", v[2] == "c" -// -// See StrSplit() below for more information. -#ifndef ABSL_STRINGS_STR_SPLIT_H_ -#define ABSL_STRINGS_STR_SPLIT_H_ - -#include <algorithm> -#include <cstddef> -#include <map> -#include <set> +// // Can also use "," +// // v[0] == "a", v[1] == "b", v[2] == "c" +// +// See StrSplit() below for more information. +#ifndef ABSL_STRINGS_STR_SPLIT_H_ +#define ABSL_STRINGS_STR_SPLIT_H_ + +#include <algorithm> +#include <cstddef> +#include <map> +#include <set> #include <util/generic/string.h> -#include <utility> -#include <vector> - +#include <utility> +#include <vector> + #include "y_absl/base/internal/raw_logging.h" #include "y_absl/base/macros.h" #include "y_absl/strings/internal/str_split_internal.h" #include "y_absl/strings/string_view.h" #include "y_absl/strings/strip.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -//------------------------------------------------------------------------------ -// Delimiters -//------------------------------------------------------------------------------ -// -// `StrSplit()` uses delimiters to define the boundaries between elements in the -// provided input. Several `Delimiter` types are defined below. If a string + +//------------------------------------------------------------------------------ +// Delimiters +//------------------------------------------------------------------------------ +// +// `StrSplit()` uses delimiters to define the boundaries between elements in the +// provided input. Several `Delimiter` types are defined below. If a string // (`const char*`, `TString`, or `y_absl::string_view`) is passed in place of -// an explicit `Delimiter` object, `StrSplit()` treats it the same way as if it -// were passed a `ByString` delimiter. -// -// A `Delimiter` is an object with a `Find()` function that knows how to find +// an explicit `Delimiter` object, `StrSplit()` treats it the same way as if it +// were passed a `ByString` delimiter. +// +// A `Delimiter` is an object with a `Find()` function that knows how to find // the first occurrence of itself in a given `y_absl::string_view`. -// -// The following `Delimiter` types are available for use within `StrSplit()`: -// -// - `ByString` (default for string arguments) -// - `ByChar` (default for a char argument) -// - `ByAnyChar` -// - `ByLength` -// - `MaxSplits` -// -// A Delimiter's `Find()` member function will be passed an input `text` that is -// to be split and a position (`pos`) to begin searching for the next delimiter +// +// The following `Delimiter` types are available for use within `StrSplit()`: +// +// - `ByString` (default for string arguments) +// - `ByChar` (default for a char argument) +// - `ByAnyChar` +// - `ByLength` +// - `MaxSplits` +// +// A Delimiter's `Find()` member function will be passed an input `text` that is +// to be split and a position (`pos`) to begin searching for the next delimiter // in `text`. The returned y_absl::string_view should refer to the next occurrence // (after `pos`) of the represented delimiter; this returned y_absl::string_view -// represents the next location where the input `text` should be broken. -// +// represents the next location where the input `text` should be broken. +// // The returned y_absl::string_view may be zero-length if the Delimiter does not -// represent a part of the string (e.g., a fixed-length delimiter). If no +// represent a part of the string (e.g., a fixed-length delimiter). If no // delimiter is found in the input `text`, a zero-length y_absl::string_view -// referring to `text.end()` should be returned (e.g., -// `text.substr(text.size())`). It is important that the returned +// referring to `text.end()` should be returned (e.g., +// `text.substr(text.size())`). It is important that the returned // y_absl::string_view always be within the bounds of the input `text` given as an -// argument--it must not refer to a string that is physically located outside of -// the given string. -// -// The following example is a simple Delimiter object that is created with a -// single char and will look for that char in the text passed to the `Find()` -// function: -// -// struct SimpleDelimiter { -// const char c_; -// explicit SimpleDelimiter(char c) : c_(c) {} +// argument--it must not refer to a string that is physically located outside of +// the given string. +// +// The following example is a simple Delimiter object that is created with a +// single char and will look for that char in the text passed to the `Find()` +// function: +// +// struct SimpleDelimiter { +// const char c_; +// explicit SimpleDelimiter(char c) : c_(c) {} // y_absl::string_view Find(y_absl::string_view text, size_t pos) { -// auto found = text.find(c_, pos); +// auto found = text.find(c_, pos); // if (found == y_absl::string_view::npos) -// return text.substr(text.size()); -// -// return text.substr(found, 1); -// } -// }; - -// ByString -// -// A sub-string delimiter. If `StrSplit()` is passed a string in place of a -// `Delimiter` object, the string will be implicitly converted into a -// `ByString` delimiter. -// -// Example: -// +// return text.substr(text.size()); +// +// return text.substr(found, 1); +// } +// }; + +// ByString +// +// A sub-string delimiter. If `StrSplit()` is passed a string in place of a +// `Delimiter` object, the string will be implicitly converted into a +// `ByString` delimiter. +// +// Example: +// // // Because a string literal is converted to an `y_absl::ByString`, -// // the following two splits are equivalent. -// +// // the following two splits are equivalent. +// // std::vector<TString> v1 = y_absl::StrSplit("a, b, c", ", "); -// +// // using y_absl::ByString; // std::vector<TString> v2 = y_absl::StrSplit("a, b, c", -// ByString(", ")); -// // v[0] == "a", v[1] == "b", v[2] == "c" -class ByString { - public: +// ByString(", ")); +// // v[0] == "a", v[1] == "b", v[2] == "c" +class ByString { + public: explicit ByString(y_absl::string_view sp); y_absl::string_view Find(y_absl::string_view text, size_t pos) const; - - private: + + private: const TString delimiter_; -}; - -// ByChar -// -// A single character delimiter. `ByChar` is functionally equivalent to a -// 1-char string within a `ByString` delimiter, but slightly more efficient. -// -// Example: -// +}; + +// ByChar +// +// A single character delimiter. `ByChar` is functionally equivalent to a +// 1-char string within a `ByString` delimiter, but slightly more efficient. +// +// Example: +// // // Because a char literal is converted to a y_absl::ByChar, -// // the following two splits are equivalent. +// // the following two splits are equivalent. // std::vector<TString> v1 = y_absl::StrSplit("a,b,c", ','); // using y_absl::ByChar; // std::vector<TString> v2 = y_absl::StrSplit("a,b,c", ByChar(',')); -// // v[0] == "a", v[1] == "b", v[2] == "c" -// -// `ByChar` is also the default delimiter if a single character is given -// as the delimiter to `StrSplit()`. For example, the following calls are -// equivalent: -// +// // v[0] == "a", v[1] == "b", v[2] == "c" +// +// `ByChar` is also the default delimiter if a single character is given +// as the delimiter to `StrSplit()`. For example, the following calls are +// equivalent: +// // std::vector<TString> v = y_absl::StrSplit("a-b", '-'); -// +// // using y_absl::ByChar; // std::vector<TString> v = y_absl::StrSplit("a-b", ByChar('-')); -// -class ByChar { - public: - explicit ByChar(char c) : c_(c) {} +// +class ByChar { + public: + explicit ByChar(char c) : c_(c) {} y_absl::string_view Find(y_absl::string_view text, size_t pos) const; - - private: - char c_; -}; - -// ByAnyChar -// -// A delimiter that will match any of the given byte-sized characters within -// its provided string. -// -// Note: this delimiter works with single-byte string data, but does not work -// with variable-width encodings, such as UTF-8. -// -// Example: -// + + private: + char c_; +}; + +// ByAnyChar +// +// A delimiter that will match any of the given byte-sized characters within +// its provided string. +// +// Note: this delimiter works with single-byte string data, but does not work +// with variable-width encodings, such as UTF-8. +// +// Example: +// // using y_absl::ByAnyChar; // std::vector<TString> v = y_absl::StrSplit("a,b=c", ByAnyChar(",=")); -// // v[0] == "a", v[1] == "b", v[2] == "c" -// -// If `ByAnyChar` is given the empty string, it behaves exactly like -// `ByString` and matches each individual character in the input string. -// -class ByAnyChar { - public: +// // v[0] == "a", v[1] == "b", v[2] == "c" +// +// If `ByAnyChar` is given the empty string, it behaves exactly like +// `ByString` and matches each individual character in the input string. +// +class ByAnyChar { + public: explicit ByAnyChar(y_absl::string_view sp); y_absl::string_view Find(y_absl::string_view text, size_t pos) const; - - private: + + private: const TString delimiters_; -}; - -// ByLength -// -// A delimiter for splitting into equal-length strings. The length argument to -// the constructor must be greater than 0. -// -// Note: this delimiter works with single-byte string data, but does not work -// with variable-width encodings, such as UTF-8. -// -// Example: -// +}; + +// ByLength +// +// A delimiter for splitting into equal-length strings. The length argument to +// the constructor must be greater than 0. +// +// Note: this delimiter works with single-byte string data, but does not work +// with variable-width encodings, such as UTF-8. +// +// Example: +// // using y_absl::ByLength; // std::vector<TString> v = y_absl::StrSplit("123456789", ByLength(3)); - -// // v[0] == "123", v[1] == "456", v[2] == "789" -// -// Note that the string does not have to be a multiple of the fixed split -// length. In such a case, the last substring will be shorter. -// + +// // v[0] == "123", v[1] == "456", v[2] == "789" +// +// Note that the string does not have to be a multiple of the fixed split +// length. In such a case, the last substring will be shorter. +// // using y_absl::ByLength; // std::vector<TString> v = y_absl::StrSplit("12345", ByLength(2)); -// -// // v[0] == "12", v[1] == "34", v[2] == "5" -class ByLength { - public: - explicit ByLength(ptrdiff_t length); +// +// // v[0] == "12", v[1] == "34", v[2] == "5" +class ByLength { + public: + explicit ByLength(ptrdiff_t length); y_absl::string_view Find(y_absl::string_view text, size_t pos) const; - - private: - const ptrdiff_t length_; -}; - -namespace strings_internal { - -// A traits-like metafunction for selecting the default Delimiter object type -// for a particular Delimiter type. The base case simply exposes type Delimiter -// itself as the delimiter's Type. However, there are specializations for -// string-like objects that map them to the ByString delimiter object. + + private: + const ptrdiff_t length_; +}; + +namespace strings_internal { + +// A traits-like metafunction for selecting the default Delimiter object type +// for a particular Delimiter type. The base case simply exposes type Delimiter +// itself as the delimiter's Type. However, there are specializations for +// string-like objects that map them to the ByString delimiter object. // This allows functions like y_absl::StrSplit() and y_absl::MaxSplits() to accept -// string-like objects (e.g., ',') as delimiter arguments but they will be -// treated as if a ByString delimiter was given. -template <typename Delimiter> -struct SelectDelimiter { - using type = Delimiter; -}; - -template <> -struct SelectDelimiter<char> { - using type = ByChar; -}; -template <> -struct SelectDelimiter<char*> { - using type = ByString; -}; -template <> -struct SelectDelimiter<const char*> { - using type = ByString; -}; -template <> +// string-like objects (e.g., ',') as delimiter arguments but they will be +// treated as if a ByString delimiter was given. +template <typename Delimiter> +struct SelectDelimiter { + using type = Delimiter; +}; + +template <> +struct SelectDelimiter<char> { + using type = ByChar; +}; +template <> +struct SelectDelimiter<char*> { + using type = ByString; +}; +template <> +struct SelectDelimiter<const char*> { + using type = ByString; +}; +template <> struct SelectDelimiter<y_absl::string_view> { - using type = ByString; -}; -template <> + using type = ByString; +}; +template <> struct SelectDelimiter<TString> { - using type = ByString; -}; - -// Wraps another delimiter and sets a max number of matches for that delimiter. -template <typename Delimiter> -class MaxSplitsImpl { - public: - MaxSplitsImpl(Delimiter delimiter, int limit) - : delimiter_(delimiter), limit_(limit), count_(0) {} + using type = ByString; +}; + +// Wraps another delimiter and sets a max number of matches for that delimiter. +template <typename Delimiter> +class MaxSplitsImpl { + public: + MaxSplitsImpl(Delimiter delimiter, int limit) + : delimiter_(delimiter), limit_(limit), count_(0) {} y_absl::string_view Find(y_absl::string_view text, size_t pos) { - if (count_++ == limit_) { + if (count_++ == limit_) { return y_absl::string_view(text.data() + text.size(), - 0); // No more matches. - } - return delimiter_.Find(text, pos); - } - - private: - Delimiter delimiter_; - const int limit_; - int count_; -}; - -} // namespace strings_internal - -// MaxSplits() -// -// A delimiter that limits the number of matches which can occur to the passed -// `limit`. The last element in the returned collection will contain all -// remaining unsplit pieces, which may contain instances of the delimiter. -// The collection will contain at most `limit` + 1 elements. -// Example: -// + 0); // No more matches. + } + return delimiter_.Find(text, pos); + } + + private: + Delimiter delimiter_; + const int limit_; + int count_; +}; + +} // namespace strings_internal + +// MaxSplits() +// +// A delimiter that limits the number of matches which can occur to the passed +// `limit`. The last element in the returned collection will contain all +// remaining unsplit pieces, which may contain instances of the delimiter. +// The collection will contain at most `limit` + 1 elements. +// Example: +// // using y_absl::MaxSplits; // std::vector<TString> v = y_absl::StrSplit("a,b,c", MaxSplits(',', 1)); -// -// // v[0] == "a", v[1] == "b,c" -template <typename Delimiter> -inline strings_internal::MaxSplitsImpl< - typename strings_internal::SelectDelimiter<Delimiter>::type> -MaxSplits(Delimiter delimiter, int limit) { - typedef - typename strings_internal::SelectDelimiter<Delimiter>::type DelimiterType; - return strings_internal::MaxSplitsImpl<DelimiterType>( - DelimiterType(delimiter), limit); -} - -//------------------------------------------------------------------------------ -// Predicates -//------------------------------------------------------------------------------ -// -// Predicates filter the results of a `StrSplit()` by determining whether or not -// a resultant element is included in the result set. A predicate may be passed -// as an optional third argument to the `StrSplit()` function. -// -// Predicates are unary functions (or functors) that take a single +// +// // v[0] == "a", v[1] == "b,c" +template <typename Delimiter> +inline strings_internal::MaxSplitsImpl< + typename strings_internal::SelectDelimiter<Delimiter>::type> +MaxSplits(Delimiter delimiter, int limit) { + typedef + typename strings_internal::SelectDelimiter<Delimiter>::type DelimiterType; + return strings_internal::MaxSplitsImpl<DelimiterType>( + DelimiterType(delimiter), limit); +} + +//------------------------------------------------------------------------------ +// Predicates +//------------------------------------------------------------------------------ +// +// Predicates filter the results of a `StrSplit()` by determining whether or not +// a resultant element is included in the result set. A predicate may be passed +// as an optional third argument to the `StrSplit()` function. +// +// Predicates are unary functions (or functors) that take a single // `y_absl::string_view` argument and return a bool indicating whether the -// argument should be included (`true`) or excluded (`false`). -// -// Predicates are useful when filtering out empty substrings. By default, empty -// substrings may be returned by `StrSplit()`, which is similar to the way split -// functions work in other programming languages. - -// AllowEmpty() -// -// Always returns `true`, indicating that all strings--including empty -// strings--should be included in the split output. This predicate is not -// strictly needed because this is the default behavior of `StrSplit()`; -// however, it might be useful at some call sites to make the intent explicit. -// -// Example: -// +// argument should be included (`true`) or excluded (`false`). +// +// Predicates are useful when filtering out empty substrings. By default, empty +// substrings may be returned by `StrSplit()`, which is similar to the way split +// functions work in other programming languages. + +// AllowEmpty() +// +// Always returns `true`, indicating that all strings--including empty +// strings--should be included in the split output. This predicate is not +// strictly needed because this is the default behavior of `StrSplit()`; +// however, it might be useful at some call sites to make the intent explicit. +// +// Example: +// // std::vector<TString> v = y_absl::StrSplit(" a , ,,b,", ',', AllowEmpty()); -// -// // v[0] == " a ", v[1] == " ", v[2] == "", v[3] = "b", v[4] == "" -struct AllowEmpty { +// +// // v[0] == " a ", v[1] == " ", v[2] == "", v[3] = "b", v[4] == "" +struct AllowEmpty { bool operator()(y_absl::string_view) const { return true; } -}; - -// SkipEmpty() -// +}; + +// SkipEmpty() +// // Returns `false` if the given `y_absl::string_view` is empty, indicating that -// `StrSplit()` should omit the empty string. -// -// Example: -// +// `StrSplit()` should omit the empty string. +// +// Example: +// // std::vector<TString> v = y_absl::StrSplit(",a,,b,", ',', SkipEmpty()); -// -// // v[0] == "a", v[1] == "b" -// -// Note: `SkipEmpty()` does not consider a string containing only whitespace -// to be empty. To skip such whitespace as well, use the `SkipWhitespace()` -// predicate. -struct SkipEmpty { +// +// // v[0] == "a", v[1] == "b" +// +// Note: `SkipEmpty()` does not consider a string containing only whitespace +// to be empty. To skip such whitespace as well, use the `SkipWhitespace()` +// predicate. +struct SkipEmpty { bool operator()(y_absl::string_view sp) const { return !sp.empty(); } -}; - -// SkipWhitespace() -// +}; + +// SkipWhitespace() +// // Returns `false` if the given `y_absl::string_view` is empty *or* contains only -// whitespace, indicating that `StrSplit()` should omit the string. -// -// Example: -// +// whitespace, indicating that `StrSplit()` should omit the string. +// +// Example: +// // std::vector<TString> v = y_absl::StrSplit(" a , ,,b,", -// ',', SkipWhitespace()); -// // v[0] == " a ", v[1] == "b" -// -// // SkipEmpty() would return whitespace elements +// ',', SkipWhitespace()); +// // v[0] == " a ", v[1] == "b" +// +// // SkipEmpty() would return whitespace elements // std::vector<TString> v = y_absl::StrSplit(" a , ,,b,", ',', SkipEmpty()); -// // v[0] == " a ", v[1] == " ", v[2] == "b" -struct SkipWhitespace { +// // v[0] == " a ", v[1] == " ", v[2] == "b" +struct SkipWhitespace { bool operator()(y_absl::string_view sp) const { sp = y_absl::StripAsciiWhitespace(sp); - return !sp.empty(); - } -}; - + return !sp.empty(); + } +}; + template <typename T> using EnableSplitIfString = typename std::enable_if<std::is_same<T, TString>::value || std::is_same<T, const TString>::value, int>::type; -//------------------------------------------------------------------------------ -// StrSplit() -//------------------------------------------------------------------------------ - -// StrSplit() -// -// Splits a given string based on the provided `Delimiter` object, returning the -// elements within the type specified by the caller. Optionally, you may pass a -// `Predicate` to `StrSplit()` indicating whether to include or exclude the -// resulting element within the final result set. (See the overviews for -// Delimiters and Predicates above.) -// -// Example: -// +//------------------------------------------------------------------------------ +// StrSplit() +//------------------------------------------------------------------------------ + +// StrSplit() +// +// Splits a given string based on the provided `Delimiter` object, returning the +// elements within the type specified by the caller. Optionally, you may pass a +// `Predicate` to `StrSplit()` indicating whether to include or exclude the +// resulting element within the final result set. (See the overviews for +// Delimiters and Predicates above.) +// +// Example: +// // std::vector<TString> v = y_absl::StrSplit("a,b,c,d", ','); -// // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d" -// -// You can also provide an explicit `Delimiter` object: -// -// Example: -// +// // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d" +// +// You can also provide an explicit `Delimiter` object: +// +// Example: +// // using y_absl::ByAnyChar; // std::vector<TString> v = y_absl::StrSplit("a,b=c", ByAnyChar(",=")); -// // v[0] == "a", v[1] == "b", v[2] == "c" -// -// See above for more information on delimiters. -// -// By default, empty strings are included in the result set. You can optionally -// include a third `Predicate` argument to apply a test for whether the -// resultant element should be included in the result set: -// -// Example: -// +// // v[0] == "a", v[1] == "b", v[2] == "c" +// +// See above for more information on delimiters. +// +// By default, empty strings are included in the result set. You can optionally +// include a third `Predicate` argument to apply a test for whether the +// resultant element should be included in the result set: +// +// Example: +// // std::vector<TString> v = y_absl::StrSplit(" a , ,,b,", -// ',', SkipWhitespace()); -// // v[0] == " a ", v[1] == "b" -// -// See above for more information on predicates. -// -//------------------------------------------------------------------------------ -// StrSplit() Return Types -//------------------------------------------------------------------------------ -// -// The `StrSplit()` function adapts the returned collection to the collection -// specified by the caller (e.g. `std::vector` above). The returned collections +// ',', SkipWhitespace()); +// // v[0] == " a ", v[1] == "b" +// +// See above for more information on predicates. +// +//------------------------------------------------------------------------------ +// StrSplit() Return Types +//------------------------------------------------------------------------------ +// +// The `StrSplit()` function adapts the returned collection to the collection +// specified by the caller (e.g. `std::vector` above). The returned collections // may contain `TString`, `y_absl::string_view` (in which case the original -// string being split must ensure that it outlives the collection), or any +// string being split must ensure that it outlives the collection), or any // object that can be explicitly created from an `y_absl::string_view`. This -// behavior works for: -// -// 1) All standard STL containers including `std::vector`, `std::list`, -// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap` -// 2) `std::pair` (which is not actually a container). See below. -// -// Example: -// +// behavior works for: +// +// 1) All standard STL containers including `std::vector`, `std::list`, +// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap` +// 2) `std::pair` (which is not actually a container). See below. +// +// Example: +// // // The results are returned as `y_absl::string_view` objects. Note that we -// // have to ensure that the input string outlives any results. +// // have to ensure that the input string outlives any results. // std::vector<y_absl::string_view> v = y_absl::StrSplit("a,b,c", ','); -// +// // // Stores results in a std::set<TString>, which also performs -// // de-duplication and orders the elements in ascending order. +// // de-duplication and orders the elements in ascending order. // std::set<TString> a = y_absl::StrSplit("b,a,c,a,b", ','); -// // v[0] == "a", v[1] == "b", v[2] = "c" -// -// // `StrSplit()` can be used within a range-based for loop, in which case +// // v[0] == "a", v[1] == "b", v[2] = "c" +// +// // `StrSplit()` can be used within a range-based for loop, in which case // // each element will be of type `y_absl::string_view`. // std::vector<TString> v; // for (const auto sv : y_absl::StrSplit("a,b,c", ',')) { -// if (sv != "b") v.emplace_back(sv); -// } -// // v[0] == "a", v[1] == "c" -// -// // Stores results in a map. The map implementation assumes that the input -// // is provided as a series of key/value pairs. For example, the 0th element -// // resulting from the split will be stored as a key to the 1st element. If -// // an odd number of elements are resolved, the last element is paired with -// // a default-constructed value (e.g., empty string). +// if (sv != "b") v.emplace_back(sv); +// } +// // v[0] == "a", v[1] == "c" +// +// // Stores results in a map. The map implementation assumes that the input +// // is provided as a series of key/value pairs. For example, the 0th element +// // resulting from the split will be stored as a key to the 1st element. If +// // an odd number of elements are resolved, the last element is paired with +// // a default-constructed value (e.g., empty string). // std::map<TString, TString> m = y_absl::StrSplit("a,b,c", ','); -// // m["a"] == "b", m["c"] == "" // last component value equals "" -// -// Splitting to `std::pair` is an interesting case because it can hold only two -// elements and is not a collection type. When splitting to a `std::pair` the -// first two split strings become the `std::pair` `.first` and `.second` -// members, respectively. The remaining split substrings are discarded. If there -// are less than two split substrings, the empty string is used for the -// corresponding -// `std::pair` member. -// -// Example: -// -// // Stores first two split strings as the members in a std::pair. +// // m["a"] == "b", m["c"] == "" // last component value equals "" +// +// Splitting to `std::pair` is an interesting case because it can hold only two +// elements and is not a collection type. When splitting to a `std::pair` the +// first two split strings become the `std::pair` `.first` and `.second` +// members, respectively. The remaining split substrings are discarded. If there +// are less than two split substrings, the empty string is used for the +// corresponding +// `std::pair` member. +// +// Example: +// +// // Stores first two split strings as the members in a std::pair. // std::pair<TString, TString> p = y_absl::StrSplit("a,b,c", ','); -// // p.first == "a", p.second == "b" // "c" is omitted. -// -// The `StrSplit()` function can be used multiple times to perform more -// complicated splitting logic, such as intelligently parsing key-value pairs. -// -// Example: -// -// // The input string "a=b=c,d=e,f=,g" becomes -// // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" } +// // p.first == "a", p.second == "b" // "c" is omitted. +// +// The `StrSplit()` function can be used multiple times to perform more +// complicated splitting logic, such as intelligently parsing key-value pairs. +// +// Example: +// +// // The input string "a=b=c,d=e,f=,g" becomes +// // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" } // std::map<TString, TString> m; // for (y_absl::string_view sp : y_absl::StrSplit("a=b=c,d=e,f=,g", ',')) { // m.insert(y_absl::StrSplit(sp, y_absl::MaxSplits('=', 1))); -// } -// EXPECT_EQ("b=c", m.find("a")->second); -// EXPECT_EQ("e", m.find("d")->second); -// EXPECT_EQ("", m.find("f")->second); -// EXPECT_EQ("", m.find("g")->second); -// -// WARNING: Due to a legacy bug that is maintained for backward compatibility, -// splitting the following empty string_views produces different results: -// +// } +// EXPECT_EQ("b=c", m.find("a")->second); +// EXPECT_EQ("e", m.find("d")->second); +// EXPECT_EQ("", m.find("f")->second); +// EXPECT_EQ("", m.find("g")->second); +// +// WARNING: Due to a legacy bug that is maintained for backward compatibility, +// splitting the following empty string_views produces different results: +// // y_absl::StrSplit(y_absl::string_view(""), '-'); // {""} // y_absl::StrSplit(y_absl::string_view(), '-'); // {}, but should be {""} -// -// Try not to depend on this distinction because the bug may one day be fixed. -template <typename Delimiter> -strings_internal::Splitter< +// +// Try not to depend on this distinction because the bug may one day be fixed. +template <typename Delimiter> +strings_internal::Splitter< typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty, y_absl::string_view> -StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) { - using DelimiterType = - typename strings_internal::SelectDelimiter<Delimiter>::type; +StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) { + using DelimiterType = + typename strings_internal::SelectDelimiter<Delimiter>::type; return strings_internal::Splitter<DelimiterType, AllowEmpty, y_absl::string_view>( text.value(), DelimiterType(d), AllowEmpty()); @@ -514,17 +514,17 @@ StrSplit(StringType&& text, Delimiter d) { using DelimiterType = typename strings_internal::SelectDelimiter<Delimiter>::type; return strings_internal::Splitter<DelimiterType, AllowEmpty, TString>( - std::move(text), DelimiterType(d), AllowEmpty()); -} - -template <typename Delimiter, typename Predicate> -strings_internal::Splitter< + std::move(text), DelimiterType(d), AllowEmpty()); +} + +template <typename Delimiter, typename Predicate> +strings_internal::Splitter< typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate, y_absl::string_view> -StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d, - Predicate p) { - using DelimiterType = - typename strings_internal::SelectDelimiter<Delimiter>::type; +StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d, + Predicate p) { + using DelimiterType = + typename strings_internal::SelectDelimiter<Delimiter>::type; return strings_internal::Splitter<DelimiterType, Predicate, y_absl::string_view>( text.value(), DelimiterType(d), std::move(p)); @@ -539,10 +539,10 @@ StrSplit(StringType&& text, Delimiter d, Predicate p) { using DelimiterType = typename strings_internal::SelectDelimiter<Delimiter>::type; return strings_internal::Splitter<DelimiterType, Predicate, TString>( - std::move(text), DelimiterType(d), std::move(p)); -} - + std::move(text), DelimiterType(d), std::move(p)); +} + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_STR_SPLIT_H_ + +#endif // ABSL_STRINGS_STR_SPLIT_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.cc index 9893c7ab99..6515cc7a2a 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.cc @@ -1,230 +1,230 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/string_view.h" - -#ifndef ABSL_USES_STD_STRING_VIEW - -#include <algorithm> -#include <climits> -#include <cstring> -#include <ostream> - + +#ifndef ABSL_USES_STD_STRING_VIEW + +#include <algorithm> +#include <climits> +#include <cstring> +#include <ostream> + #include "y_absl/strings/internal/memutil.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -namespace { -void WritePadding(std::ostream& o, size_t pad) { - char fill_buf[32]; - memset(fill_buf, o.fill(), sizeof(fill_buf)); - while (pad) { - size_t n = std::min(pad, sizeof(fill_buf)); - o.write(fill_buf, n); - pad -= n; - } -} - -class LookupTable { - public: - // For each character in wanted, sets the index corresponding - // to the ASCII code of that character. This is used by - // the find_.*_of methods below to tell whether or not a character is in - // the lookup table in constant time. - explicit LookupTable(string_view wanted) { - for (char c : wanted) { - table_[Index(c)] = true; - } - } - bool operator[](char c) const { return table_[Index(c)]; } - - private: - static unsigned char Index(char c) { return static_cast<unsigned char>(c); } - bool table_[UCHAR_MAX + 1] = {}; -}; - -} // namespace - -std::ostream& operator<<(std::ostream& o, string_view piece) { - std::ostream::sentry sentry(o); - if (sentry) { - size_t lpad = 0; - size_t rpad = 0; - if (static_cast<size_t>(o.width()) > piece.size()) { - size_t pad = o.width() - piece.size(); - if ((o.flags() & o.adjustfield) == o.left) { - rpad = pad; - } else { - lpad = pad; - } - } - if (lpad) WritePadding(o, lpad); - o.write(piece.data(), piece.size()); - if (rpad) WritePadding(o, rpad); - o.width(0); - } - return o; -} - + +namespace { +void WritePadding(std::ostream& o, size_t pad) { + char fill_buf[32]; + memset(fill_buf, o.fill(), sizeof(fill_buf)); + while (pad) { + size_t n = std::min(pad, sizeof(fill_buf)); + o.write(fill_buf, n); + pad -= n; + } +} + +class LookupTable { + public: + // For each character in wanted, sets the index corresponding + // to the ASCII code of that character. This is used by + // the find_.*_of methods below to tell whether or not a character is in + // the lookup table in constant time. + explicit LookupTable(string_view wanted) { + for (char c : wanted) { + table_[Index(c)] = true; + } + } + bool operator[](char c) const { return table_[Index(c)]; } + + private: + static unsigned char Index(char c) { return static_cast<unsigned char>(c); } + bool table_[UCHAR_MAX + 1] = {}; +}; + +} // namespace + +std::ostream& operator<<(std::ostream& o, string_view piece) { + std::ostream::sentry sentry(o); + if (sentry) { + size_t lpad = 0; + size_t rpad = 0; + if (static_cast<size_t>(o.width()) > piece.size()) { + size_t pad = o.width() - piece.size(); + if ((o.flags() & o.adjustfield) == o.left) { + rpad = pad; + } else { + lpad = pad; + } + } + if (lpad) WritePadding(o, lpad); + o.write(piece.data(), piece.size()); + if (rpad) WritePadding(o, rpad); + o.width(0); + } + return o; +} + string_view::size_type string_view::find(string_view s, size_type pos) const noexcept { - if (empty() || pos > length_) { - if (empty() && pos == 0 && s.empty()) return 0; - return npos; - } - const char* result = - strings_internal::memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_); - return result ? result - ptr_ : npos; -} - -string_view::size_type string_view::find(char c, size_type pos) const noexcept { - if (empty() || pos >= length_) { - return npos; - } - const char* result = - static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos)); - return result != nullptr ? result - ptr_ : npos; -} - + if (empty() || pos > length_) { + if (empty() && pos == 0 && s.empty()) return 0; + return npos; + } + const char* result = + strings_internal::memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_); + return result ? result - ptr_ : npos; +} + +string_view::size_type string_view::find(char c, size_type pos) const noexcept { + if (empty() || pos >= length_) { + return npos; + } + const char* result = + static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos)); + return result != nullptr ? result - ptr_ : npos; +} + string_view::size_type string_view::rfind(string_view s, size_type pos) const noexcept { - if (length_ < s.length_) return npos; - if (s.empty()) return std::min(length_, pos); - const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; - const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); - return result != last ? result - ptr_ : npos; -} - -// Search range is [0..pos] inclusive. If pos == npos, search everything. + if (length_ < s.length_) return npos; + if (s.empty()) return std::min(length_, pos); + const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; + const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); + return result != last ? result - ptr_ : npos; +} + +// Search range is [0..pos] inclusive. If pos == npos, search everything. string_view::size_type string_view::rfind(char c, size_type pos) const noexcept { - // Note: memrchr() is not available on Windows. - if (empty()) return npos; - for (size_type i = std::min(pos, length_ - 1);; --i) { - if (ptr_[i] == c) { - return i; - } - if (i == 0) break; - } - return npos; -} - + // Note: memrchr() is not available on Windows. + if (empty()) return npos; + for (size_type i = std::min(pos, length_ - 1);; --i) { + if (ptr_[i] == c) { + return i; + } + if (i == 0) break; + } + return npos; +} + string_view::size_type string_view::find_first_of( string_view s, size_type pos) const noexcept { - if (empty() || s.empty()) { - return npos; - } - // Avoid the cost of LookupTable() for a single-character search. - if (s.length_ == 1) return find_first_of(s.ptr_[0], pos); - LookupTable tbl(s); - for (size_type i = pos; i < length_; ++i) { - if (tbl[ptr_[i]]) { - return i; - } - } - return npos; -} - + if (empty() || s.empty()) { + return npos; + } + // Avoid the cost of LookupTable() for a single-character search. + if (s.length_ == 1) return find_first_of(s.ptr_[0], pos); + LookupTable tbl(s); + for (size_type i = pos; i < length_; ++i) { + if (tbl[ptr_[i]]) { + return i; + } + } + return npos; +} + string_view::size_type string_view::find_first_not_of( string_view s, size_type pos) const noexcept { - if (empty()) return npos; - // Avoid the cost of LookupTable() for a single-character search. - if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos); - LookupTable tbl(s); - for (size_type i = pos; i < length_; ++i) { - if (!tbl[ptr_[i]]) { - return i; - } - } - return npos; -} - + if (empty()) return npos; + // Avoid the cost of LookupTable() for a single-character search. + if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos); + LookupTable tbl(s); + for (size_type i = pos; i < length_; ++i) { + if (!tbl[ptr_[i]]) { + return i; + } + } + return npos; +} + string_view::size_type string_view::find_first_not_of( char c, size_type pos) const noexcept { - if (empty()) return npos; - for (; pos < length_; ++pos) { - if (ptr_[pos] != c) { - return pos; - } - } - return npos; -} - -string_view::size_type string_view::find_last_of(string_view s, - size_type pos) const noexcept { - if (empty() || s.empty()) return npos; - // Avoid the cost of LookupTable() for a single-character search. - if (s.length_ == 1) return find_last_of(s.ptr_[0], pos); - LookupTable tbl(s); - for (size_type i = std::min(pos, length_ - 1);; --i) { - if (tbl[ptr_[i]]) { - return i; - } - if (i == 0) break; - } - return npos; -} - + if (empty()) return npos; + for (; pos < length_; ++pos) { + if (ptr_[pos] != c) { + return pos; + } + } + return npos; +} + +string_view::size_type string_view::find_last_of(string_view s, + size_type pos) const noexcept { + if (empty() || s.empty()) return npos; + // Avoid the cost of LookupTable() for a single-character search. + if (s.length_ == 1) return find_last_of(s.ptr_[0], pos); + LookupTable tbl(s); + for (size_type i = std::min(pos, length_ - 1);; --i) { + if (tbl[ptr_[i]]) { + return i; + } + if (i == 0) break; + } + return npos; +} + string_view::size_type string_view::find_last_not_of( string_view s, size_type pos) const noexcept { - if (empty()) return npos; - size_type i = std::min(pos, length_ - 1); - if (s.empty()) return i; - // Avoid the cost of LookupTable() for a single-character search. - if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos); - LookupTable tbl(s); - for (;; --i) { - if (!tbl[ptr_[i]]) { - return i; - } - if (i == 0) break; - } - return npos; -} - + if (empty()) return npos; + size_type i = std::min(pos, length_ - 1); + if (s.empty()) return i; + // Avoid the cost of LookupTable() for a single-character search. + if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos); + LookupTable tbl(s); + for (;; --i) { + if (!tbl[ptr_[i]]) { + return i; + } + if (i == 0) break; + } + return npos; +} + string_view::size_type string_view::find_last_not_of( char c, size_type pos) const noexcept { - if (empty()) return npos; - size_type i = std::min(pos, length_ - 1); - for (;; --i) { - if (ptr_[i] != c) { - return i; - } - if (i == 0) break; - } - return npos; -} - -// MSVC has non-standard behavior that implicitly creates definitions for static -// const members. These implicit definitions conflict with explicit out-of-class -// member definitions that are required by the C++ standard, resulting in -// LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks -// MSVC to choose only one definition for the symbol it decorates. See details -// at https://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx -#ifdef _MSC_VER -#define ABSL_STRING_VIEW_SELECTANY __declspec(selectany) -#else -#define ABSL_STRING_VIEW_SELECTANY -#endif - -ABSL_STRING_VIEW_SELECTANY -constexpr string_view::size_type string_view::npos; -ABSL_STRING_VIEW_SELECTANY -constexpr string_view::size_type string_view::kMaxSize; - + if (empty()) return npos; + size_type i = std::min(pos, length_ - 1); + for (;; --i) { + if (ptr_[i] != c) { + return i; + } + if (i == 0) break; + } + return npos; +} + +// MSVC has non-standard behavior that implicitly creates definitions for static +// const members. These implicit definitions conflict with explicit out-of-class +// member definitions that are required by the C++ standard, resulting in +// LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks +// MSVC to choose only one definition for the symbol it decorates. See details +// at https://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx +#ifdef _MSC_VER +#define ABSL_STRING_VIEW_SELECTANY __declspec(selectany) +#else +#define ABSL_STRING_VIEW_SELECTANY +#endif + +ABSL_STRING_VIEW_SELECTANY +constexpr string_view::size_type string_view::npos; +ABSL_STRING_VIEW_SELECTANY +constexpr string_view::size_type string_view::kMaxSize; + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_USES_STD_STRING_VIEW + +#endif // ABSL_USES_STD_STRING_VIEW diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.h index c3906fe1c5..97caf6ebc9 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.h @@ -1,33 +1,33 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: string_view.h -// ----------------------------------------------------------------------------- -// +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: string_view.h +// ----------------------------------------------------------------------------- +// // This file contains the definition of the `y_absl::string_view` class. A -// `string_view` points to a contiguous span of characters, often part or all of +// `string_view` points to a contiguous span of characters, often part or all of // another `TString`, double-quoted string literal, character array, or even -// another `string_view`. -// +// another `string_view`. +// // This `y_absl::string_view` abstraction is designed to be a drop-in -// replacement for the C++17 `std::string_view` abstraction. -#ifndef ABSL_STRINGS_STRING_VIEW_H_ -#define ABSL_STRINGS_STRING_VIEW_H_ - -#include <algorithm> +// replacement for the C++17 `std::string_view` abstraction. +#ifndef ABSL_STRINGS_STRING_VIEW_H_ +#define ABSL_STRINGS_STRING_VIEW_H_ + +#include <algorithm> #include <cassert> #include <cstddef> #include <cstring> @@ -42,28 +42,28 @@ #include "y_absl/base/macros.h" #include "y_absl/base/optimization.h" #include "y_absl/base/port.h" - -#ifdef ABSL_USES_STD_STRING_VIEW - -#include <string_view> // IWYU pragma: export - + +#ifdef ABSL_USES_STD_STRING_VIEW + +#include <string_view> // IWYU pragma: export + namespace y_absl { ABSL_NAMESPACE_BEGIN using string_view = std::string_view; ABSL_NAMESPACE_END } // namespace y_absl - -#else // ABSL_USES_STD_STRING_VIEW - + +#else // ABSL_USES_STD_STRING_VIEW + #error "std::string_view should be used in all configurations" -#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \ - (defined(__GNUC__) && !defined(__clang__)) -#define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp -#else // ABSL_HAVE_BUILTIN(__builtin_memcmp) -#define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp -#endif // ABSL_HAVE_BUILTIN(__builtin_memcmp) - +#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \ + (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp +#else // ABSL_HAVE_BUILTIN(__builtin_memcmp) +#define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp +#endif // ABSL_HAVE_BUILTIN(__builtin_memcmp) + #if defined(__cplusplus) && __cplusplus >= 201402L #define ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR constexpr #else @@ -72,54 +72,54 @@ ABSL_NAMESPACE_END namespace y_absl { ABSL_NAMESPACE_BEGIN - + // y_absl::string_view -// -// A `string_view` provides a lightweight view into the string data provided by +// +// A `string_view` provides a lightweight view into the string data provided by // a `TString`, double-quoted string literal, character array, or even -// another `string_view`. A `string_view` does *not* own the string to which it -// points, and that data cannot be modified through the view. -// -// You can use `string_view` as a function or method parameter anywhere a -// parameter can receive a double-quoted string literal, `const char*`, +// another `string_view`. A `string_view` does *not* own the string to which it +// points, and that data cannot be modified through the view. +// +// You can use `string_view` as a function or method parameter anywhere a +// parameter can receive a double-quoted string literal, `const char*`, // `TString`, or another `y_absl::string_view` argument with no need to copy -// the string data. Systematic use of `string_view` within function arguments -// reduces data copies and `strlen()` calls. -// -// Because of its small size, prefer passing `string_view` by value: -// +// the string data. Systematic use of `string_view` within function arguments +// reduces data copies and `strlen()` calls. +// +// Because of its small size, prefer passing `string_view` by value: +// // void MyFunction(y_absl::string_view arg); -// -// If circumstances require, you may also pass one by const reference: -// +// +// If circumstances require, you may also pass one by const reference: +// // void MyFunction(const y_absl::string_view& arg); // not preferred -// -// Passing by value generates slightly smaller code for many architectures. -// -// In either case, the source data of the `string_view` must outlive the -// `string_view` itself. -// -// A `string_view` is also suitable for local variables if you know that the -// lifetime of the underlying object is longer than the lifetime of your -// `string_view` variable. However, beware of binding a `string_view` to a -// temporary value: -// -// // BAD use of string_view: lifetime problem +// +// Passing by value generates slightly smaller code for many architectures. +// +// In either case, the source data of the `string_view` must outlive the +// `string_view` itself. +// +// A `string_view` is also suitable for local variables if you know that the +// lifetime of the underlying object is longer than the lifetime of your +// `string_view` variable. However, beware of binding a `string_view` to a +// temporary value: +// +// // BAD use of string_view: lifetime problem // y_absl::string_view sv = obj.ReturnAString(); -// -// // GOOD use of string_view: str outlives sv +// +// // GOOD use of string_view: str outlives sv // TString str = obj.ReturnAString(); // y_absl::string_view sv = str; -// -// Due to lifetime issues, a `string_view` is sometimes a poor choice for a -// return value and usually a poor choice for a data member. If you do use a -// `string_view` this way, it is your responsibility to ensure that the object -// pointed to by the `string_view` outlives the `string_view`. -// -// A `string_view` may represent a whole string or just part of a string. For +// +// Due to lifetime issues, a `string_view` is sometimes a poor choice for a +// return value and usually a poor choice for a data member. If you do use a +// `string_view` this way, it is your responsibility to ensure that the object +// pointed to by the `string_view` outlives the `string_view`. +// +// A `string_view` may represent a whole string or just part of a string. For // example, when splitting a string, `std::vector<y_absl::string_view>` is a -// natural data type for the output. -// +// natural data type for the output. +// // For another example, a Cord is a non-contiguous, potentially very // long string-like object. The Cord class has an interface that iteratively // provides string_view objects that point to the successive pieces of a Cord @@ -129,273 +129,273 @@ ABSL_NAMESPACE_BEGIN // itself will not include the NUL-terminator unless a specific size (including // the NUL) is passed to the constructor. As a result, common idioms that work // on NUL-terminated strings do not work on `string_view` objects. If you write -// code that scans a `string_view`, you must check its length rather than test -// for nul, for example. Note, however, that nuls may still be embedded within -// a `string_view` explicitly. -// -// You may create a null `string_view` in two ways: -// +// code that scans a `string_view`, you must check its length rather than test +// for nul, for example. Note, however, that nuls may still be embedded within +// a `string_view` explicitly. +// +// You may create a null `string_view` in two ways: +// // y_absl::string_view sv; // y_absl::string_view sv(nullptr, 0); -// -// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and -// `sv.empty() == true`. Also, if you create a `string_view` with a non-null -// pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to -// signal an undefined value that is different from other `string_view` values -// in a similar fashion to how `const char* p1 = nullptr;` is different from -// `const char* p2 = "";`. However, in practice, it is not recommended to rely -// on this behavior. -// -// Be careful not to confuse a null `string_view` with an empty one. A null -// `string_view` is an empty `string_view`, but some empty `string_view`s are -// not null. Prefer checking for emptiness over checking for null. -// -// There are many ways to create an empty string_view: -// -// const char* nullcp = nullptr; -// // string_view.size() will return 0 in all cases. +// +// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and +// `sv.empty() == true`. Also, if you create a `string_view` with a non-null +// pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to +// signal an undefined value that is different from other `string_view` values +// in a similar fashion to how `const char* p1 = nullptr;` is different from +// `const char* p2 = "";`. However, in practice, it is not recommended to rely +// on this behavior. +// +// Be careful not to confuse a null `string_view` with an empty one. A null +// `string_view` is an empty `string_view`, but some empty `string_view`s are +// not null. Prefer checking for emptiness over checking for null. +// +// There are many ways to create an empty string_view: +// +// const char* nullcp = nullptr; +// // string_view.size() will return 0 in all cases. // y_absl::string_view(); // y_absl::string_view(nullcp, 0); // y_absl::string_view(""); // y_absl::string_view("", 0); // y_absl::string_view("abcdef", 0); // y_absl::string_view("abcdef" + 6, 0); -// -// All empty `string_view` objects whether null or not, are equal: -// +// +// All empty `string_view` objects whether null or not, are equal: +// // y_absl::string_view() == y_absl::string_view("", 0) // y_absl::string_view(nullptr, 0) == y_absl::string_view("abcdef"+6, 0) -class string_view { - public: - using traits_type = std::char_traits<char>; - using value_type = char; - using pointer = char*; - using const_pointer = const char*; - using reference = char&; - using const_reference = const char&; - using const_iterator = const char*; - using iterator = const_iterator; - using const_reverse_iterator = std::reverse_iterator<const_iterator>; - using reverse_iterator = const_reverse_iterator; - using size_type = size_t; - using difference_type = std::ptrdiff_t; - - static constexpr size_type npos = static_cast<size_type>(-1); - - // Null `string_view` constructor - constexpr string_view() noexcept : ptr_(nullptr), length_(0) {} - - // Implicit constructors - - template <typename Allocator> - string_view( // NOLINT(runtime/explicit) +class string_view { + public: + using traits_type = std::char_traits<char>; + using value_type = char; + using pointer = char*; + using const_pointer = const char*; + using reference = char&; + using const_reference = const char&; + using const_iterator = const char*; + using iterator = const_iterator; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using reverse_iterator = const_reverse_iterator; + using size_type = size_t; + using difference_type = std::ptrdiff_t; + + static constexpr size_type npos = static_cast<size_type>(-1); + + // Null `string_view` constructor + constexpr string_view() noexcept : ptr_(nullptr), length_(0) {} + + // Implicit constructors + + template <typename Allocator> + string_view( // NOLINT(runtime/explicit) const std::basic_string<char, std::char_traits<char>, Allocator>& str ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept - // This is implemented in terms of `string_view(p, n)` so `str.size()` - // doesn't need to be reevaluated after `ptr_` is set. + // This is implemented in terms of `string_view(p, n)` so `str.size()` + // doesn't need to be reevaluated after `ptr_` is set. // The length check is also skipped since it is unnecessary and causes // code bloat. : string_view(str.data(), str.size(), SkipCheckLengthTag{}) {} - + // Implicit constructor of a `string_view` from NUL-terminated `str`. When // accepting possibly null strings, use `y_absl::NullSafeStringView(str)` - // instead (see below). + // instead (see below). // The length check is skipped since it is unnecessary and causes code bloat. - constexpr string_view(const char* str) // NOLINT(runtime/explicit) + constexpr string_view(const char* str) // NOLINT(runtime/explicit) : ptr_(str), length_(str ? StrlenInternal(str) : 0) {} - - // Implicit constructor of a `string_view` from a `const char*` and length. - constexpr string_view(const char* data, size_type len) - : ptr_(data), length_(CheckLengthInternal(len)) {} - - // NOTE: Harmlessly omitted to work around gdb bug. - // constexpr string_view(const string_view&) noexcept = default; - // string_view& operator=(const string_view&) noexcept = default; - - // Iterators - - // string_view::begin() - // - // Returns an iterator pointing to the first character at the beginning of the - // `string_view`, or `end()` if the `string_view` is empty. - constexpr const_iterator begin() const noexcept { return ptr_; } - - // string_view::end() - // - // Returns an iterator pointing just beyond the last character at the end of - // the `string_view`. This iterator acts as a placeholder; attempting to - // access it results in undefined behavior. - constexpr const_iterator end() const noexcept { return ptr_ + length_; } - - // string_view::cbegin() - // - // Returns a const iterator pointing to the first character at the beginning - // of the `string_view`, or `end()` if the `string_view` is empty. - constexpr const_iterator cbegin() const noexcept { return begin(); } - - // string_view::cend() - // - // Returns a const iterator pointing just beyond the last character at the end - // of the `string_view`. This pointer acts as a placeholder; attempting to - // access its element results in undefined behavior. - constexpr const_iterator cend() const noexcept { return end(); } - - // string_view::rbegin() - // - // Returns a reverse iterator pointing to the last character at the end of the - // `string_view`, or `rend()` if the `string_view` is empty. - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - - // string_view::rend() - // - // Returns a reverse iterator pointing just before the first character at the - // beginning of the `string_view`. This pointer acts as a placeholder; - // attempting to access its element results in undefined behavior. - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } - - // string_view::crbegin() - // - // Returns a const reverse iterator pointing to the last character at the end - // of the `string_view`, or `crend()` if the `string_view` is empty. - const_reverse_iterator crbegin() const noexcept { return rbegin(); } - - // string_view::crend() - // - // Returns a const reverse iterator pointing just before the first character - // at the beginning of the `string_view`. This pointer acts as a placeholder; - // attempting to access its element results in undefined behavior. - const_reverse_iterator crend() const noexcept { return rend(); } - - // Capacity Utilities - - // string_view::size() - // - // Returns the number of characters in the `string_view`. + + // Implicit constructor of a `string_view` from a `const char*` and length. + constexpr string_view(const char* data, size_type len) + : ptr_(data), length_(CheckLengthInternal(len)) {} + + // NOTE: Harmlessly omitted to work around gdb bug. + // constexpr string_view(const string_view&) noexcept = default; + // string_view& operator=(const string_view&) noexcept = default; + + // Iterators + + // string_view::begin() + // + // Returns an iterator pointing to the first character at the beginning of the + // `string_view`, or `end()` if the `string_view` is empty. + constexpr const_iterator begin() const noexcept { return ptr_; } + + // string_view::end() + // + // Returns an iterator pointing just beyond the last character at the end of + // the `string_view`. This iterator acts as a placeholder; attempting to + // access it results in undefined behavior. + constexpr const_iterator end() const noexcept { return ptr_ + length_; } + + // string_view::cbegin() + // + // Returns a const iterator pointing to the first character at the beginning + // of the `string_view`, or `end()` if the `string_view` is empty. + constexpr const_iterator cbegin() const noexcept { return begin(); } + + // string_view::cend() + // + // Returns a const iterator pointing just beyond the last character at the end + // of the `string_view`. This pointer acts as a placeholder; attempting to + // access its element results in undefined behavior. + constexpr const_iterator cend() const noexcept { return end(); } + + // string_view::rbegin() + // + // Returns a reverse iterator pointing to the last character at the end of the + // `string_view`, or `rend()` if the `string_view` is empty. + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } + + // string_view::rend() + // + // Returns a reverse iterator pointing just before the first character at the + // beginning of the `string_view`. This pointer acts as a placeholder; + // attempting to access its element results in undefined behavior. + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } + + // string_view::crbegin() + // + // Returns a const reverse iterator pointing to the last character at the end + // of the `string_view`, or `crend()` if the `string_view` is empty. + const_reverse_iterator crbegin() const noexcept { return rbegin(); } + + // string_view::crend() + // + // Returns a const reverse iterator pointing just before the first character + // at the beginning of the `string_view`. This pointer acts as a placeholder; + // attempting to access its element results in undefined behavior. + const_reverse_iterator crend() const noexcept { return rend(); } + + // Capacity Utilities + + // string_view::size() + // + // Returns the number of characters in the `string_view`. constexpr size_type size() const noexcept { return length_; } - - // string_view::length() - // - // Returns the number of characters in the `string_view`. Alias for `size()`. - constexpr size_type length() const noexcept { return size(); } - - // string_view::max_size() - // - // Returns the maximum number of characters the `string_view` can hold. - constexpr size_type max_size() const noexcept { return kMaxSize; } - - // string_view::empty() - // - // Checks if the `string_view` is empty (refers to no characters). - constexpr bool empty() const noexcept { return length_ == 0; } - - // string_view::operator[] - // - // Returns the ith element of the `string_view` using the array operator. - // Note that this operator does not perform any bounds checking. + + // string_view::length() + // + // Returns the number of characters in the `string_view`. Alias for `size()`. + constexpr size_type length() const noexcept { return size(); } + + // string_view::max_size() + // + // Returns the maximum number of characters the `string_view` can hold. + constexpr size_type max_size() const noexcept { return kMaxSize; } + + // string_view::empty() + // + // Checks if the `string_view` is empty (refers to no characters). + constexpr bool empty() const noexcept { return length_ == 0; } + + // string_view::operator[] + // + // Returns the ith element of the `string_view` using the array operator. + // Note that this operator does not perform any bounds checking. constexpr const_reference operator[](size_type i) const { return ABSL_HARDENING_ASSERT(i < size()), ptr_[i]; } - - // string_view::at() - // - // Returns the ith element of the `string_view`. Bounds checking is performed, - // and an exception of type `std::out_of_range` will be thrown on invalid - // access. - constexpr const_reference at(size_type i) const { - return ABSL_PREDICT_TRUE(i < size()) - ? ptr_[i] - : ((void)base_internal::ThrowStdOutOfRange( + + // string_view::at() + // + // Returns the ith element of the `string_view`. Bounds checking is performed, + // and an exception of type `std::out_of_range` will be thrown on invalid + // access. + constexpr const_reference at(size_type i) const { + return ABSL_PREDICT_TRUE(i < size()) + ? ptr_[i] + : ((void)base_internal::ThrowStdOutOfRange( "y_absl::string_view::at"), - ptr_[i]); - } - - // string_view::front() - // - // Returns the first element of a `string_view`. + ptr_[i]); + } + + // string_view::front() + // + // Returns the first element of a `string_view`. constexpr const_reference front() const { return ABSL_HARDENING_ASSERT(!empty()), ptr_[0]; } - - // string_view::back() - // - // Returns the last element of a `string_view`. + + // string_view::back() + // + // Returns the last element of a `string_view`. constexpr const_reference back() const { return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1]; } - - // string_view::data() - // - // Returns a pointer to the underlying character array (which is of course - // stored elsewhere). Note that `string_view::data()` may contain embedded nul + + // string_view::data() + // + // Returns a pointer to the underlying character array (which is of course + // stored elsewhere). Note that `string_view::data()` may contain embedded nul // characters, but the returned buffer may or may not be NUL-terminated; // therefore, do not pass `data()` to a routine that expects a NUL-terminated // string. - constexpr const_pointer data() const noexcept { return ptr_; } - - // Modifiers - - // string_view::remove_prefix() - // - // Removes the first `n` characters from the `string_view`. Note that the + constexpr const_pointer data() const noexcept { return ptr_; } + + // Modifiers + + // string_view::remove_prefix() + // + // Removes the first `n` characters from the `string_view`. Note that the // underlying string is not changed, only the view. ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_prefix(size_type n) { ABSL_HARDENING_ASSERT(n <= length_); - ptr_ += n; - length_ -= n; - } - - // string_view::remove_suffix() - // - // Removes the last `n` characters from the `string_view`. Note that the + ptr_ += n; + length_ -= n; + } + + // string_view::remove_suffix() + // + // Removes the last `n` characters from the `string_view`. Note that the // underlying string is not changed, only the view. ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_suffix(size_type n) { ABSL_HARDENING_ASSERT(n <= length_); - length_ -= n; - } - - // string_view::swap() - // - // Swaps this `string_view` with another `string_view`. + length_ -= n; + } + + // string_view::swap() + // + // Swaps this `string_view` with another `string_view`. ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void swap(string_view& s) noexcept { - auto t = *this; - *this = s; - s = t; - } - - // Explicit conversion operators - - // Converts to `std::basic_string`. - template <typename A> - explicit operator std::basic_string<char, traits_type, A>() const { - if (!data()) return {}; - return std::basic_string<char, traits_type, A>(data(), size()); - } - - // string_view::copy() - // - // Copies the contents of the `string_view` at offset `pos` and length `n` - // into `buf`. - size_type copy(char* buf, size_type n, size_type pos = 0) const { - if (ABSL_PREDICT_FALSE(pos > length_)) { + auto t = *this; + *this = s; + s = t; + } + + // Explicit conversion operators + + // Converts to `std::basic_string`. + template <typename A> + explicit operator std::basic_string<char, traits_type, A>() const { + if (!data()) return {}; + return std::basic_string<char, traits_type, A>(data(), size()); + } + + // string_view::copy() + // + // Copies the contents of the `string_view` at offset `pos` and length `n` + // into `buf`. + size_type copy(char* buf, size_type n, size_type pos = 0) const { + if (ABSL_PREDICT_FALSE(pos > length_)) { base_internal::ThrowStdOutOfRange("y_absl::string_view::copy"); - } - size_type rlen = (std::min)(length_ - pos, n); - if (rlen > 0) { - const char* start = ptr_ + pos; - traits_type::copy(buf, start, rlen); - } - return rlen; - } - - // string_view::substr() - // - // Returns a "substring" of the `string_view` (at offset `pos` and length - // `n`) as another string_view. This function throws `std::out_of_bounds` if - // `pos > size`. + } + size_type rlen = (std::min)(length_ - pos, n); + if (rlen > 0) { + const char* start = ptr_ + pos; + traits_type::copy(buf, start, rlen); + } + return rlen; + } + + // string_view::substr() + // + // Returns a "substring" of the `string_view` (at offset `pos` and length + // `n`) as another string_view. This function throws `std::out_of_bounds` if + // `pos > size`. // Use y_absl::ClippedSubstr if you need a truncating substr operation. constexpr string_view substr(size_type pos = 0, size_type n = npos) const { return ABSL_PREDICT_FALSE(pos > length_) @@ -403,65 +403,65 @@ class string_view { "y_absl::string_view::substr"), string_view()) : string_view(ptr_ + pos, Min(n, length_ - pos)); - } - - // string_view::compare() - // + } + + // string_view::compare() + // // Performs a lexicographical comparison between this `string_view` and // another `string_view` `x`, returning a negative value if `*this` is less // than `x`, 0 if `*this` is equal to `x`, and a positive value if `*this` // is greater than `x`. - constexpr int compare(string_view x) const noexcept { + constexpr int compare(string_view x) const noexcept { return CompareImpl(length_, x.length_, Min(length_, x.length_) == 0 ? 0 : ABSL_INTERNAL_STRING_VIEW_MEMCMP( ptr_, x.ptr_, Min(length_, x.length_))); - } - - // Overload of `string_view::compare()` for comparing a substring of the + } + + // Overload of `string_view::compare()` for comparing a substring of the // 'string_view` and another `y_absl::string_view`. constexpr int compare(size_type pos1, size_type count1, string_view v) const { - return substr(pos1, count1).compare(v); - } - - // Overload of `string_view::compare()` for comparing a substring of the + return substr(pos1, count1).compare(v); + } + + // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a substring of another `y_absl::string_view`. constexpr int compare(size_type pos1, size_type count1, string_view v, size_type pos2, size_type count2) const { - return substr(pos1, count1).compare(v.substr(pos2, count2)); - } - - // Overload of `string_view::compare()` for comparing a `string_view` and a + return substr(pos1, count1).compare(v.substr(pos2, count2)); + } + + // Overload of `string_view::compare()` for comparing a `string_view` and a // a different C-style string `s`. constexpr int compare(const char* s) const { return compare(string_view(s)); } - - // Overload of `string_view::compare()` for comparing a substring of the + + // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a different string C-style string `s`. constexpr int compare(size_type pos1, size_type count1, const char* s) const { - return substr(pos1, count1).compare(string_view(s)); - } - - // Overload of `string_view::compare()` for comparing a substring of the + return substr(pos1, count1).compare(string_view(s)); + } + + // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a substring of a different C-style string `s`. constexpr int compare(size_type pos1, size_type count1, const char* s, size_type count2) const { - return substr(pos1, count1).compare(string_view(s, count2)); - } - - // Find Utilities - - // string_view::find() - // - // Finds the first occurrence of the substring `s` within the `string_view`, - // returning the position of the first character's match, or `npos` if no - // match was found. - size_type find(string_view s, size_type pos = 0) const noexcept; - - // Overload of `string_view::find()` for finding the given character `c` - // within the `string_view`. - size_type find(char c, size_type pos = 0) const noexcept; - + return substr(pos1, count1).compare(string_view(s, count2)); + } + + // Find Utilities + + // string_view::find() + // + // Finds the first occurrence of the substring `s` within the `string_view`, + // returning the position of the first character's match, or `npos` if no + // match was found. + size_type find(string_view s, size_type pos = 0) const noexcept; + + // Overload of `string_view::find()` for finding the given character `c` + // within the `string_view`. + size_type find(char c, size_type pos = 0) const noexcept; + // Overload of `string_view::find()` for finding a substring of a different // C-style string `s` within the `string_view`. size_type find(const char* s, size_type pos, size_type count) const { @@ -474,17 +474,17 @@ class string_view { return find(string_view(s), pos); } - // string_view::rfind() - // - // Finds the last occurrence of a substring `s` within the `string_view`, - // returning the position of the first character's match, or `npos` if no - // match was found. + // string_view::rfind() + // + // Finds the last occurrence of a substring `s` within the `string_view`, + // returning the position of the first character's match, or `npos` if no + // match was found. size_type rfind(string_view s, size_type pos = npos) const noexcept; - - // Overload of `string_view::rfind()` for finding the last given character `c` - // within the `string_view`. - size_type rfind(char c, size_type pos = npos) const noexcept; - + + // Overload of `string_view::rfind()` for finding the last given character `c` + // within the `string_view`. + size_type rfind(char c, size_type pos = npos) const noexcept; + // Overload of `string_view::rfind()` for finding a substring of a different // C-style string `s` within the `string_view`. size_type rfind(const char* s, size_type pos, size_type count) const { @@ -497,19 +497,19 @@ class string_view { return rfind(string_view(s), pos); } - // string_view::find_first_of() - // - // Finds the first occurrence of any of the characters in `s` within the - // `string_view`, returning the start position of the match, or `npos` if no - // match was found. + // string_view::find_first_of() + // + // Finds the first occurrence of any of the characters in `s` within the + // `string_view`, returning the start position of the match, or `npos` if no + // match was found. size_type find_first_of(string_view s, size_type pos = 0) const noexcept; - - // Overload of `string_view::find_first_of()` for finding a character `c` - // within the `string_view`. + + // Overload of `string_view::find_first_of()` for finding a character `c` + // within the `string_view`. size_type find_first_of(char c, size_type pos = 0) const noexcept { - return find(c, pos); - } - + return find(c, pos); + } + // Overload of `string_view::find_first_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_first_of(const char* s, size_type pos, @@ -523,19 +523,19 @@ class string_view { return find_first_of(string_view(s), pos); } - // string_view::find_last_of() - // - // Finds the last occurrence of any of the characters in `s` within the - // `string_view`, returning the start position of the match, or `npos` if no - // match was found. + // string_view::find_last_of() + // + // Finds the last occurrence of any of the characters in `s` within the + // `string_view`, returning the start position of the match, or `npos` if no + // match was found. size_type find_last_of(string_view s, size_type pos = npos) const noexcept; - - // Overload of `string_view::find_last_of()` for finding a character `c` - // within the `string_view`. + + // Overload of `string_view::find_last_of()` for finding a character `c` + // within the `string_view`. size_type find_last_of(char c, size_type pos = npos) const noexcept { - return rfind(c, pos); - } - + return rfind(c, pos); + } + // Overload of `string_view::find_last_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_last_of(const char* s, size_type pos, size_type count) const { @@ -548,17 +548,17 @@ class string_view { return find_last_of(string_view(s), pos); } - // string_view::find_first_not_of() - // - // Finds the first occurrence of any of the characters not in `s` within the - // `string_view`, returning the start position of the first non-match, or - // `npos` if no non-match was found. - size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept; - - // Overload of `string_view::find_first_not_of()` for finding a character - // that is not `c` within the `string_view`. - size_type find_first_not_of(char c, size_type pos = 0) const noexcept; - + // string_view::find_first_not_of() + // + // Finds the first occurrence of any of the characters not in `s` within the + // `string_view`, returning the start position of the first non-match, or + // `npos` if no non-match was found. + size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept; + + // Overload of `string_view::find_first_not_of()` for finding a character + // that is not `c` within the `string_view`. + size_type find_first_not_of(char c, size_type pos = 0) const noexcept; + // Overload of `string_view::find_first_not_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_first_not_of(const char* s, size_type pos, @@ -572,18 +572,18 @@ class string_view { return find_first_not_of(string_view(s), pos); } - // string_view::find_last_not_of() - // - // Finds the last occurrence of any of the characters not in `s` within the - // `string_view`, returning the start position of the last non-match, or - // `npos` if no non-match was found. - size_type find_last_not_of(string_view s, + // string_view::find_last_not_of() + // + // Finds the last occurrence of any of the characters not in `s` within the + // `string_view`, returning the start position of the last non-match, or + // `npos` if no non-match was found. + size_type find_last_not_of(string_view s, size_type pos = npos) const noexcept; - - // Overload of `string_view::find_last_not_of()` for finding a character - // that is not `c` within the `string_view`. + + // Overload of `string_view::find_last_not_of()` for finding a character + // that is not `c` within the `string_view`. size_type find_last_not_of(char c, size_type pos = npos) const noexcept; - + // Overload of `string_view::find_last_not_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_last_not_of(const char* s, size_type pos, @@ -597,116 +597,116 @@ class string_view { return find_last_not_of(string_view(s), pos); } - private: + private: // The constructor from TString delegates to this constructor. // See the comment on that constructor for the rationale. struct SkipCheckLengthTag {}; string_view(const char* data, size_type len, SkipCheckLengthTag) noexcept : ptr_(data), length_(len) {} - static constexpr size_type kMaxSize = - (std::numeric_limits<difference_type>::max)(); - - static constexpr size_type CheckLengthInternal(size_type len) { + static constexpr size_type kMaxSize = + (std::numeric_limits<difference_type>::max)(); + + static constexpr size_type CheckLengthInternal(size_type len) { return ABSL_HARDENING_ASSERT(len <= kMaxSize), len; - } - - static constexpr size_type StrlenInternal(const char* str) { -#if defined(_MSC_VER) && _MSC_VER >= 1910 && !defined(__clang__) - // MSVC 2017+ can evaluate this at compile-time. - const char* begin = str; - while (*str != '\0') ++str; - return str - begin; -#elif ABSL_HAVE_BUILTIN(__builtin_strlen) || \ - (defined(__GNUC__) && !defined(__clang__)) - // GCC has __builtin_strlen according to - // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but - // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above. - // __builtin_strlen is constexpr. - return __builtin_strlen(str); -#else - return str ? strlen(str) : 0; -#endif - } - + } + + static constexpr size_type StrlenInternal(const char* str) { +#if defined(_MSC_VER) && _MSC_VER >= 1910 && !defined(__clang__) + // MSVC 2017+ can evaluate this at compile-time. + const char* begin = str; + while (*str != '\0') ++str; + return str - begin; +#elif ABSL_HAVE_BUILTIN(__builtin_strlen) || \ + (defined(__GNUC__) && !defined(__clang__)) + // GCC has __builtin_strlen according to + // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but + // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above. + // __builtin_strlen is constexpr. + return __builtin_strlen(str); +#else + return str ? strlen(str) : 0; +#endif + } + static constexpr size_t Min(size_type length_a, size_type length_b) { return length_a < length_b ? length_a : length_b; } - static constexpr int CompareImpl(size_type length_a, size_type length_b, - int compare_result) { - return compare_result == 0 ? static_cast<int>(length_a > length_b) - - static_cast<int>(length_a < length_b) + static constexpr int CompareImpl(size_type length_a, size_type length_b, + int compare_result) { + return compare_result == 0 ? static_cast<int>(length_a > length_b) - + static_cast<int>(length_a < length_b) : (compare_result < 0 ? -1 : 1); - } - - const char* ptr_; - size_type length_; -}; - -// This large function is defined inline so that in a fairly common case where -// one of the arguments is a literal, the compiler can elide a lot of the -// following comparisons. -constexpr bool operator==(string_view x, string_view y) noexcept { - return x.size() == y.size() && - (x.empty() || - ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0); -} - -constexpr bool operator!=(string_view x, string_view y) noexcept { - return !(x == y); -} - -constexpr bool operator<(string_view x, string_view y) noexcept { - return x.compare(y) < 0; -} - -constexpr bool operator>(string_view x, string_view y) noexcept { - return y < x; -} - -constexpr bool operator<=(string_view x, string_view y) noexcept { - return !(y < x); -} - -constexpr bool operator>=(string_view x, string_view y) noexcept { - return !(x < y); -} - -// IO Insertion Operator -std::ostream& operator<<(std::ostream& o, string_view piece); - + } + + const char* ptr_; + size_type length_; +}; + +// This large function is defined inline so that in a fairly common case where +// one of the arguments is a literal, the compiler can elide a lot of the +// following comparisons. +constexpr bool operator==(string_view x, string_view y) noexcept { + return x.size() == y.size() && + (x.empty() || + ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0); +} + +constexpr bool operator!=(string_view x, string_view y) noexcept { + return !(x == y); +} + +constexpr bool operator<(string_view x, string_view y) noexcept { + return x.compare(y) < 0; +} + +constexpr bool operator>(string_view x, string_view y) noexcept { + return y < x; +} + +constexpr bool operator<=(string_view x, string_view y) noexcept { + return !(y < x); +} + +constexpr bool operator>=(string_view x, string_view y) noexcept { + return !(x < y); +} + +// IO Insertion Operator +std::ostream& operator<<(std::ostream& o, string_view piece); + ABSL_NAMESPACE_END } // namespace y_absl - + #undef ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR -#undef ABSL_INTERNAL_STRING_VIEW_MEMCMP - -#endif // ABSL_USES_STD_STRING_VIEW - +#undef ABSL_INTERNAL_STRING_VIEW_MEMCMP + +#endif // ABSL_USES_STD_STRING_VIEW + namespace y_absl { ABSL_NAMESPACE_BEGIN - -// ClippedSubstr() -// -// Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`. -// Provided because std::string_view::substr throws if `pos > size()` -inline string_view ClippedSubstr(string_view s, size_t pos, - size_t n = string_view::npos) { - pos = (std::min)(pos, static_cast<size_t>(s.size())); - return s.substr(pos, n); -} - -// NullSafeStringView() -// + +// ClippedSubstr() +// +// Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`. +// Provided because std::string_view::substr throws if `pos > size()` +inline string_view ClippedSubstr(string_view s, size_t pos, + size_t n = string_view::npos) { + pos = (std::min)(pos, static_cast<size_t>(s.size())); + return s.substr(pos, n); +} + +// NullSafeStringView() +// // Creates an `y_absl::string_view` from a pointer `p` even if it's null-valued. // This function should be used where an `y_absl::string_view` can be created from -// a possibly-null pointer. +// a possibly-null pointer. constexpr string_view NullSafeStringView(const char* p) { - return p ? string_view(p) : string_view(); -} - + return p ? string_view(p) : string_view(); +} + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_STRING_VIEW_H_ + +#endif // ABSL_STRINGS_STRING_VIEW_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/strip.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/strip.h index 3164ff1ebc..b766b75d2a 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/strip.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/strip.h @@ -1,91 +1,91 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: strip.h -// ----------------------------------------------------------------------------- -// -// This file contains various functions for stripping substrings from a string. -#ifndef ABSL_STRINGS_STRIP_H_ -#define ABSL_STRINGS_STRIP_H_ - -#include <cstddef> +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: strip.h +// ----------------------------------------------------------------------------- +// +// This file contains various functions for stripping substrings from a string. +#ifndef ABSL_STRINGS_STRIP_H_ +#define ABSL_STRINGS_STRIP_H_ + +#include <cstddef> #include <util/generic/string.h> - + #include "y_absl/base/macros.h" #include "y_absl/strings/ascii.h" #include "y_absl/strings/match.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN - -// ConsumePrefix() -// -// Strips the `expected` prefix from the start of the given string, returning -// `true` if the strip operation succeeded or false otherwise. -// -// Example: -// + +// ConsumePrefix() +// +// Strips the `expected` prefix from the start of the given string, returning +// `true` if the strip operation succeeded or false otherwise. +// +// Example: +// // y_absl::string_view input("abc"); // EXPECT_TRUE(y_absl::ConsumePrefix(&input, "a")); -// EXPECT_EQ(input, "bc"); +// EXPECT_EQ(input, "bc"); inline bool ConsumePrefix(y_absl::string_view* str, y_absl::string_view expected) { if (!y_absl::StartsWith(*str, expected)) return false; - str->remove_prefix(expected.size()); - return true; -} -// ConsumeSuffix() -// -// Strips the `expected` suffix from the end of the given string, returning -// `true` if the strip operation succeeded or false otherwise. -// -// Example: -// + str->remove_prefix(expected.size()); + return true; +} +// ConsumeSuffix() +// +// Strips the `expected` suffix from the end of the given string, returning +// `true` if the strip operation succeeded or false otherwise. +// +// Example: +// // y_absl::string_view input("abcdef"); // EXPECT_TRUE(y_absl::ConsumeSuffix(&input, "def")); -// EXPECT_EQ(input, "abc"); +// EXPECT_EQ(input, "abc"); inline bool ConsumeSuffix(y_absl::string_view* str, y_absl::string_view expected) { if (!y_absl::EndsWith(*str, expected)) return false; - str->remove_suffix(expected.size()); - return true; -} - -// StripPrefix() -// -// Returns a view into the input string 'str' with the given 'prefix' removed, -// but leaving the original string intact. If the prefix does not match at the -// start of the string, returns the original string instead. + str->remove_suffix(expected.size()); + return true; +} + +// StripPrefix() +// +// Returns a view into the input string 'str' with the given 'prefix' removed, +// but leaving the original string intact. If the prefix does not match at the +// start of the string, returns the original string instead. ABSL_MUST_USE_RESULT inline y_absl::string_view StripPrefix( y_absl::string_view str, y_absl::string_view prefix) { if (y_absl::StartsWith(str, prefix)) str.remove_prefix(prefix.size()); - return str; -} - -// StripSuffix() -// -// Returns a view into the input string 'str' with the given 'suffix' removed, -// but leaving the original string intact. If the suffix does not match at the -// end of the string, returns the original string instead. + return str; +} + +// StripSuffix() +// +// Returns a view into the input string 'str' with the given 'suffix' removed, +// but leaving the original string intact. If the suffix does not match at the +// end of the string, returns the original string instead. ABSL_MUST_USE_RESULT inline y_absl::string_view StripSuffix( y_absl::string_view str, y_absl::string_view suffix) { if (y_absl::EndsWith(str, suffix)) str.remove_suffix(suffix.size()); - return str; -} - + return str; +} + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_STRIP_H_ + +#endif // ABSL_STRINGS_STRIP_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.cc index 177fba8cbe..45cdf0e467 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.cc @@ -1,172 +1,172 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/substitute.h" - -#include <algorithm> - + +#include <algorithm> + #include "y_absl/base/internal/raw_logging.h" #include "y_absl/strings/ascii.h" #include "y_absl/strings/escaping.h" #include "y_absl/strings/internal/resize_uninitialized.h" #include "y_absl/strings/string_view.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace substitute_internal { - +namespace substitute_internal { + void SubstituteAndAppendArray(TString* output, y_absl::string_view format, const y_absl::string_view* args_array, - size_t num_args) { - // Determine total size needed. - size_t size = 0; - for (size_t i = 0; i < format.size(); i++) { - if (format[i] == '$') { - if (i + 1 >= format.size()) { -#ifndef NDEBUG - ABSL_RAW_LOG(FATAL, + size_t num_args) { + // Determine total size needed. + size_t size = 0; + for (size_t i = 0; i < format.size(); i++) { + if (format[i] == '$') { + if (i + 1 >= format.size()) { +#ifndef NDEBUG + ABSL_RAW_LOG(FATAL, "Invalid y_absl::Substitute() format string: \"%s\".", y_absl::CEscape(format).c_str()); -#endif - return; +#endif + return; } else if (y_absl::ascii_isdigit(format[i + 1])) { - int index = format[i + 1] - '0'; - if (static_cast<size_t>(index) >= num_args) { -#ifndef NDEBUG - ABSL_RAW_LOG( - FATAL, + int index = format[i + 1] - '0'; + if (static_cast<size_t>(index) >= num_args) { +#ifndef NDEBUG + ABSL_RAW_LOG( + FATAL, "Invalid y_absl::Substitute() format string: asked for \"$" "%d\", but only %d args were given. Full format string was: " - "\"%s\".", + "\"%s\".", index, static_cast<int>(num_args), y_absl::CEscape(format).c_str()); -#endif - return; - } - size += args_array[index].size(); - ++i; // Skip next char. - } else if (format[i + 1] == '$') { - ++size; - ++i; // Skip next char. - } else { -#ifndef NDEBUG - ABSL_RAW_LOG(FATAL, +#endif + return; + } + size += args_array[index].size(); + ++i; // Skip next char. + } else if (format[i + 1] == '$') { + ++size; + ++i; // Skip next char. + } else { +#ifndef NDEBUG + ABSL_RAW_LOG(FATAL, "Invalid y_absl::Substitute() format string: \"%s\".", y_absl::CEscape(format).c_str()); -#endif - return; - } - } else { - ++size; - } - } - - if (size == 0) return; - +#endif + return; + } + } else { + ++size; + } + } + + if (size == 0) return; + // Build the string. - size_t original_size = output->size(); + size_t original_size = output->size(); strings_internal::STLStringResizeUninitializedAmortized(output, original_size + size); - char* target = &(*output)[original_size]; - for (size_t i = 0; i < format.size(); i++) { - if (format[i] == '$') { + char* target = &(*output)[original_size]; + for (size_t i = 0; i < format.size(); i++) { + if (format[i] == '$') { if (y_absl::ascii_isdigit(format[i + 1])) { const y_absl::string_view src = args_array[format[i + 1] - '0']; - target = std::copy(src.begin(), src.end(), target); - ++i; // Skip next char. - } else if (format[i + 1] == '$') { - *target++ = '$'; - ++i; // Skip next char. - } - } else { - *target++ = format[i]; - } - } - - assert(target == output->data() + output->size()); -} - -Arg::Arg(const void* value) { - static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2, - "fix sizeof(scratch_)"); - if (value == nullptr) { - piece_ = "NULL"; - } else { - char* ptr = scratch_ + sizeof(scratch_); - uintptr_t num = reinterpret_cast<uintptr_t>(value); - do { + target = std::copy(src.begin(), src.end(), target); + ++i; // Skip next char. + } else if (format[i + 1] == '$') { + *target++ = '$'; + ++i; // Skip next char. + } + } else { + *target++ = format[i]; + } + } + + assert(target == output->data() + output->size()); +} + +Arg::Arg(const void* value) { + static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2, + "fix sizeof(scratch_)"); + if (value == nullptr) { + piece_ = "NULL"; + } else { + char* ptr = scratch_ + sizeof(scratch_); + uintptr_t num = reinterpret_cast<uintptr_t>(value); + do { *--ptr = y_absl::numbers_internal::kHexChar[num & 0xf]; - num >>= 4; - } while (num != 0); - *--ptr = 'x'; - *--ptr = '0'; + num >>= 4; + } while (num != 0); + *--ptr = 'x'; + *--ptr = '0'; piece_ = y_absl::string_view(ptr, scratch_ + sizeof(scratch_) - ptr); - } -} - -// TODO(jorg): Don't duplicate so much code between here and str_cat.cc -Arg::Arg(Hex hex) { - char* const end = &scratch_[numbers_internal::kFastToBufferSize]; - char* writer = end; - uint64_t value = hex.value; - do { + } +} + +// TODO(jorg): Don't duplicate so much code between here and str_cat.cc +Arg::Arg(Hex hex) { + char* const end = &scratch_[numbers_internal::kFastToBufferSize]; + char* writer = end; + uint64_t value = hex.value; + do { *--writer = y_absl::numbers_internal::kHexChar[value & 0xF]; - value >>= 4; - } while (value != 0); - - char* beg; - if (end - writer < hex.width) { - beg = end - hex.width; - std::fill_n(beg, writer - beg, hex.fill); - } else { - beg = writer; - } - + value >>= 4; + } while (value != 0); + + char* beg; + if (end - writer < hex.width) { + beg = end - hex.width; + std::fill_n(beg, writer - beg, hex.fill); + } else { + beg = writer; + } + piece_ = y_absl::string_view(beg, end - beg); -} - -// TODO(jorg): Don't duplicate so much code between here and str_cat.cc -Arg::Arg(Dec dec) { - assert(dec.width <= numbers_internal::kFastToBufferSize); - char* const end = &scratch_[numbers_internal::kFastToBufferSize]; - char* const minfill = end - dec.width; - char* writer = end; - uint64_t value = dec.value; - bool neg = dec.neg; - while (value > 9) { - *--writer = '0' + (value % 10); - value /= 10; - } - *--writer = '0' + value; - if (neg) *--writer = '-'; - - ptrdiff_t fillers = writer - minfill; - if (fillers > 0) { - // Tricky: if the fill character is ' ', then it's <fill><+/-><digits> - // But...: if the fill character is '0', then it's <+/-><fill><digits> - bool add_sign_again = false; - if (neg && dec.fill == '0') { // If filling with '0', - ++writer; // ignore the sign we just added - add_sign_again = true; // and re-add the sign later. - } - writer -= fillers; - std::fill_n(writer, fillers, dec.fill); - if (add_sign_again) *--writer = '-'; - } - +} + +// TODO(jorg): Don't duplicate so much code between here and str_cat.cc +Arg::Arg(Dec dec) { + assert(dec.width <= numbers_internal::kFastToBufferSize); + char* const end = &scratch_[numbers_internal::kFastToBufferSize]; + char* const minfill = end - dec.width; + char* writer = end; + uint64_t value = dec.value; + bool neg = dec.neg; + while (value > 9) { + *--writer = '0' + (value % 10); + value /= 10; + } + *--writer = '0' + value; + if (neg) *--writer = '-'; + + ptrdiff_t fillers = writer - minfill; + if (fillers > 0) { + // Tricky: if the fill character is ' ', then it's <fill><+/-><digits> + // But...: if the fill character is '0', then it's <+/-><fill><digits> + bool add_sign_again = false; + if (neg && dec.fill == '0') { // If filling with '0', + ++writer; // ignore the sign we just added + add_sign_again = true; // and re-add the sign later. + } + writer -= fillers; + std::fill_n(writer, fillers, dec.fill); + if (add_sign_again) *--writer = '-'; + } + piece_ = y_absl::string_view(writer, end - writer); -} - -} // namespace substitute_internal +} + +} // namespace substitute_internal ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.h index c31191fbda..682030e24d 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.h @@ -1,80 +1,80 @@ -// -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: substitute.h -// ----------------------------------------------------------------------------- -// -// This package contains functions for efficiently performing string -// substitutions using a format string with positional notation: -// `Substitute()` and `SubstituteAndAppend()`. -// -// Unlike printf-style format specifiers, `Substitute()` functions do not need -// to specify the type of the substitution arguments. Supported arguments -// following the format string, such as strings, string_views, ints, -// floats, and bools, are automatically converted to strings during the -// substitution process. (See below for a full list of supported types.) -// -// `Substitute()` does not allow you to specify *how* to format a value, beyond -// the default conversion to string. For example, you cannot format an integer -// in hex. -// -// The format string uses positional identifiers indicated by a dollar sign ($) -// and single digit positional ids to indicate which substitution arguments to -// use at that location within the format string. -// -// A '$$' sequence in the format string causes a literal '$' character to be -// output. -// -// Example 1: +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: substitute.h +// ----------------------------------------------------------------------------- +// +// This package contains functions for efficiently performing string +// substitutions using a format string with positional notation: +// `Substitute()` and `SubstituteAndAppend()`. +// +// Unlike printf-style format specifiers, `Substitute()` functions do not need +// to specify the type of the substitution arguments. Supported arguments +// following the format string, such as strings, string_views, ints, +// floats, and bools, are automatically converted to strings during the +// substitution process. (See below for a full list of supported types.) +// +// `Substitute()` does not allow you to specify *how* to format a value, beyond +// the default conversion to string. For example, you cannot format an integer +// in hex. +// +// The format string uses positional identifiers indicated by a dollar sign ($) +// and single digit positional ids to indicate which substitution arguments to +// use at that location within the format string. +// +// A '$$' sequence in the format string causes a literal '$' character to be +// output. +// +// Example 1: // TString s = Substitute("$1 purchased $0 $2 for $$10. Thanks $1!", -// 5, "Bob", "Apples"); -// EXPECT_EQ("Bob purchased 5 Apples for $10. Thanks Bob!", s); -// -// Example 2: +// 5, "Bob", "Apples"); +// EXPECT_EQ("Bob purchased 5 Apples for $10. Thanks Bob!", s); +// +// Example 2: // TString s = "Hi. "; -// SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5); -// EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s); -// -// Supported types: +// SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5); +// EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s); +// +// Supported types: // * y_absl::string_view, TString, const char* (null is equivalent to "") // * int32_t, int64_t, uint32_t, uint64_t -// * float, double -// * bool (Printed as "true" or "false") -// * pointer types other than char* (Printed as "0x<lower case hex string>", -// except that null is printed as "NULL") -// -// If an invalid format string is provided, Substitute returns an empty string -// and SubstituteAndAppend does not change the provided output string. -// A format string is invalid if it: -// * ends in an unescaped $ character, -// e.g. "Hello $", or -// * calls for a position argument which is not provided, -// e.g. Substitute("Hello $2", "world"), or -// * specifies a non-digit, non-$ character after an unescaped $ character, -// e.g. "Hello $f". -// In debug mode, i.e. #ifndef NDEBUG, such errors terminate the program. - -#ifndef ABSL_STRINGS_SUBSTITUTE_H_ -#define ABSL_STRINGS_SUBSTITUTE_H_ - -#include <cstring> +// * float, double +// * bool (Printed as "true" or "false") +// * pointer types other than char* (Printed as "0x<lower case hex string>", +// except that null is printed as "NULL") +// +// If an invalid format string is provided, Substitute returns an empty string +// and SubstituteAndAppend does not change the provided output string. +// A format string is invalid if it: +// * ends in an unescaped $ character, +// e.g. "Hello $", or +// * calls for a position argument which is not provided, +// e.g. Substitute("Hello $2", "world"), or +// * specifies a non-digit, non-$ character after an unescaped $ character, +// e.g. "Hello $f". +// In debug mode, i.e. #ifndef NDEBUG, such errors terminate the program. + +#ifndef ABSL_STRINGS_SUBSTITUTE_H_ +#define ABSL_STRINGS_SUBSTITUTE_H_ + +#include <cstring> #include <util/generic/string.h> -#include <type_traits> -#include <vector> - +#include <type_traits> +#include <vector> + #include "y_absl/base/macros.h" #include "y_absl/base/port.h" #include "y_absl/strings/ascii.h" @@ -84,640 +84,640 @@ #include "y_absl/strings/str_split.h" #include "y_absl/strings/string_view.h" #include "y_absl/strings/strip.h" - + namespace y_absl { ABSL_NAMESPACE_BEGIN -namespace substitute_internal { - -// Arg -// +namespace substitute_internal { + +// Arg +// // This class provides an argument type for `y_absl::Substitute()` and // `y_absl::SubstituteAndAppend()`. `Arg` handles implicit conversion of various -// types to a string. (`Arg` is very similar to the `AlphaNum` class in -// `StrCat()`.) -// -// This class has implicit constructors. -class Arg { - public: +// types to a string. (`Arg` is very similar to the `AlphaNum` class in +// `StrCat()`.) +// +// This class has implicit constructors. +class Arg { + public: // Overloads for string-y things - // - // Explicitly overload `const char*` so the compiler doesn't cast to `bool`. - Arg(const char* value) // NOLINT(runtime/explicit) + // + // Explicitly overload `const char*` so the compiler doesn't cast to `bool`. + Arg(const char* value) // NOLINT(runtime/explicit) : piece_(y_absl::NullSafeStringView(value)) {} - template <typename Allocator> - Arg( // NOLINT - const std::basic_string<char, std::char_traits<char>, Allocator>& - value) noexcept - : piece_(value) {} + template <typename Allocator> + Arg( // NOLINT + const std::basic_string<char, std::char_traits<char>, Allocator>& + value) noexcept + : piece_(value) {} Arg(y_absl::string_view value) // NOLINT(runtime/explicit) - : piece_(value) {} + : piece_(value) {} Arg(const TString& s) : piece_(s.data(), s.size()) {} - - // Overloads for primitives - // - // No overloads are available for signed and unsigned char because if people - // are explicitly declaring their chars as signed or unsigned then they are - // probably using them as 8-bit integers and would probably prefer an integer - // representation. However, we can't really know, so we make the caller decide - // what to do. - Arg(char value) // NOLINT(runtime/explicit) + + // Overloads for primitives + // + // No overloads are available for signed and unsigned char because if people + // are explicitly declaring their chars as signed or unsigned then they are + // probably using them as 8-bit integers and would probably prefer an integer + // representation. However, we can't really know, so we make the caller decide + // what to do. + Arg(char value) // NOLINT(runtime/explicit) : piece_(scratch_, 1) { scratch_[0] = value; } - Arg(short value) // NOLINT(*) - : piece_(scratch_, - numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned short value) // NOLINT(*) - : piece_(scratch_, - numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(int value) // NOLINT(runtime/explicit) - : piece_(scratch_, - numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned int value) // NOLINT(runtime/explicit) - : piece_(scratch_, - numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(long value) // NOLINT(*) - : piece_(scratch_, - numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned long value) // NOLINT(*) - : piece_(scratch_, - numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(long long value) // NOLINT(*) - : piece_(scratch_, - numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(unsigned long long value) // NOLINT(*) - : piece_(scratch_, - numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} - Arg(float value) // NOLINT(runtime/explicit) - : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) { - } - Arg(double value) // NOLINT(runtime/explicit) - : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) { - } - Arg(bool value) // NOLINT(runtime/explicit) - : piece_(value ? "true" : "false") {} - - Arg(Hex hex); // NOLINT(runtime/explicit) - Arg(Dec dec); // NOLINT(runtime/explicit) - - // vector<bool>::reference and const_reference require special help to - // convert to `AlphaNum` because it requires two user defined conversions. - template <typename T, + Arg(short value) // NOLINT(*) + : piece_(scratch_, + numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} + Arg(unsigned short value) // NOLINT(*) + : piece_(scratch_, + numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} + Arg(int value) // NOLINT(runtime/explicit) + : piece_(scratch_, + numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} + Arg(unsigned int value) // NOLINT(runtime/explicit) + : piece_(scratch_, + numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} + Arg(long value) // NOLINT(*) + : piece_(scratch_, + numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} + Arg(unsigned long value) // NOLINT(*) + : piece_(scratch_, + numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} + Arg(long long value) // NOLINT(*) + : piece_(scratch_, + numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} + Arg(unsigned long long value) // NOLINT(*) + : piece_(scratch_, + numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} + Arg(float value) // NOLINT(runtime/explicit) + : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) { + } + Arg(double value) // NOLINT(runtime/explicit) + : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) { + } + Arg(bool value) // NOLINT(runtime/explicit) + : piece_(value ? "true" : "false") {} + + Arg(Hex hex); // NOLINT(runtime/explicit) + Arg(Dec dec); // NOLINT(runtime/explicit) + + // vector<bool>::reference and const_reference require special help to + // convert to `AlphaNum` because it requires two user defined conversions. + template <typename T, y_absl::enable_if_t< - std::is_class<T>::value && - (std::is_same<T, std::vector<bool>::reference>::value || - std::is_same<T, std::vector<bool>::const_reference>::value)>* = - nullptr> - Arg(T value) // NOLINT(google-explicit-constructor) - : Arg(static_cast<bool>(value)) {} - - // `void*` values, with the exception of `char*`, are printed as - // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed. - Arg(const void* value); // NOLINT(runtime/explicit) - - Arg(const Arg&) = delete; - Arg& operator=(const Arg&) = delete; - + std::is_class<T>::value && + (std::is_same<T, std::vector<bool>::reference>::value || + std::is_same<T, std::vector<bool>::const_reference>::value)>* = + nullptr> + Arg(T value) // NOLINT(google-explicit-constructor) + : Arg(static_cast<bool>(value)) {} + + // `void*` values, with the exception of `char*`, are printed as + // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed. + Arg(const void* value); // NOLINT(runtime/explicit) + + Arg(const Arg&) = delete; + Arg& operator=(const Arg&) = delete; + y_absl::string_view piece() const { return piece_; } - - private: + + private: y_absl::string_view piece_; - char scratch_[numbers_internal::kFastToBufferSize]; -}; - -// Internal helper function. Don't call this from outside this implementation. -// This interface may change without notice. + char scratch_[numbers_internal::kFastToBufferSize]; +}; + +// Internal helper function. Don't call this from outside this implementation. +// This interface may change without notice. void SubstituteAndAppendArray(TString* output, y_absl::string_view format, const y_absl::string_view* args_array, - size_t num_args); - -#if defined(ABSL_BAD_CALL_IF) -constexpr int CalculateOneBit(const char* format) { + size_t num_args); + +#if defined(ABSL_BAD_CALL_IF) +constexpr int CalculateOneBit(const char* format) { // Returns: // * 2^N for '$N' when N is in [0-9] // * 0 for correct '$' escaping: '$$'. // * -1 otherwise. return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1) : (1 << (*format - '0')); -} - -constexpr const char* SkipNumber(const char* format) { - return !*format ? format : (format + 1); -} - -constexpr int PlaceholderBitmask(const char* format) { +} + +constexpr const char* SkipNumber(const char* format) { + return !*format ? format : (format + 1); +} + +constexpr int PlaceholderBitmask(const char* format) { return !*format ? 0 : *format != '$' ? PlaceholderBitmask(format + 1) : (CalculateOneBit(format + 1) | PlaceholderBitmask(SkipNumber(format + 1))); -} -#endif // ABSL_BAD_CALL_IF - -} // namespace substitute_internal - -// -// PUBLIC API -// - -// SubstituteAndAppend() -// -// Substitutes variables into a given format string and appends to a given -// output string. See file comments above for usage. -// -// The declarations of `SubstituteAndAppend()` below consist of overloads -// for passing 0 to 10 arguments, respectively. -// -// NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic -// templates to allow a variable number of arguments. -// -// Example: -// template <typename... Args> +} +#endif // ABSL_BAD_CALL_IF + +} // namespace substitute_internal + +// +// PUBLIC API +// + +// SubstituteAndAppend() +// +// Substitutes variables into a given format string and appends to a given +// output string. See file comments above for usage. +// +// The declarations of `SubstituteAndAppend()` below consist of overloads +// for passing 0 to 10 arguments, respectively. +// +// NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic +// templates to allow a variable number of arguments. +// +// Example: +// template <typename... Args> // void VarMsg(TString* boilerplate, y_absl::string_view format, -// const Args&... args) { +// const Args&... args) { // y_absl::SubstituteAndAppend(boilerplate, format, args...); -// } -// +// } +// inline void SubstituteAndAppend(TString* output, y_absl::string_view format) { - substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0); -} - + substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0); +} + inline void SubstituteAndAppend(TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0) { + const substitute_internal::Arg& a0) { const y_absl::string_view args[] = {a0.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + inline void SubstituteAndAppend(TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1) { + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1) { const y_absl::string_view args[] = {a0.piece(), a1.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + inline void SubstituteAndAppend(TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2) { + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2) { const y_absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + inline void SubstituteAndAppend(TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3) { + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3) { const y_absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), - a3.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - + a3.piece()}; + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + inline void SubstituteAndAppend(TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4) { + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4) { const y_absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), - a3.piece(), a4.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - + a3.piece(), a4.piece()}; + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + inline void SubstituteAndAppend(TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5) { + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5) { const y_absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), - a3.piece(), a4.piece(), a5.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - + a3.piece(), a4.piece(), a5.piece()}; + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + inline void SubstituteAndAppend(TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6) { + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6) { const y_absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), - a3.piece(), a4.piece(), a5.piece(), - a6.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - -inline void SubstituteAndAppend( + a3.piece(), a4.piece(), a5.piece(), + a6.piece()}; + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + +inline void SubstituteAndAppend( TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) { + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) { const y_absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), - a3.piece(), a4.piece(), a5.piece(), - a6.piece(), a7.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - -inline void SubstituteAndAppend( + a3.piece(), a4.piece(), a5.piece(), + a6.piece(), a7.piece()}; + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + +inline void SubstituteAndAppend( TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6, const substitute_internal::Arg& a7, - const substitute_internal::Arg& a8) { + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6, const substitute_internal::Arg& a7, + const substitute_internal::Arg& a8) { const y_absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), - a3.piece(), a4.piece(), a5.piece(), - a6.piece(), a7.piece(), a8.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - -inline void SubstituteAndAppend( + a3.piece(), a4.piece(), a5.piece(), + a6.piece(), a7.piece(), a8.piece()}; + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + +inline void SubstituteAndAppend( TString* output, y_absl::string_view format, - const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6, const substitute_internal::Arg& a7, - const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) { + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6, const substitute_internal::Arg& a7, + const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) { const y_absl::string_view args[] = { - a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(), - a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()}; - substitute_internal::SubstituteAndAppendArray(output, format, args, - ABSL_ARRAYSIZE(args)); -} - -#if defined(ABSL_BAD_CALL_IF) -// This body of functions catches cases where the number of placeholders -// doesn't match the number of data arguments. + a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(), + a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()}; + substitute_internal::SubstituteAndAppendArray(output, format, args, + ABSL_ARRAYSIZE(args)); +} + +#if defined(ABSL_BAD_CALL_IF) +// This body of functions catches cases where the number of placeholders +// doesn't match the number of data arguments. void SubstituteAndAppend(TString* output, const char* format) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 0, "There were no substitution arguments " "but this format string either has a $[0-9] in it or contains " "an unescaped $ character (use $$ instead)"); - + void SubstituteAndAppend(TString* output, const char* format, - const substitute_internal::Arg& a0) - ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1, - "There was 1 substitution argument given, but " + const substitute_internal::Arg& a0) + ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1, + "There was 1 substitution argument given, but " "this format string is missing its $0, contains " "one of $1-$9, or contains an unescaped $ character (use " "$$ instead)"); - + void SubstituteAndAppend(TString* output, const char* format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1) + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 3, "There were 2 substitution arguments given, but this format string is " "missing its $0/$1, contains one of $2-$9, or contains an " "unescaped $ character (use $$ instead)"); - + void SubstituteAndAppend(TString* output, const char* format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2) + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 7, "There were 3 substitution arguments given, but " "this format string is missing its $0/$1/$2, contains one of " "$3-$9, or contains an unescaped $ character (use $$ instead)"); - + void SubstituteAndAppend(TString* output, const char* format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3) + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 15, "There were 4 substitution arguments given, but " "this format string is missing its $0-$3, contains one of " "$4-$9, or contains an unescaped $ character (use $$ instead)"); - + void SubstituteAndAppend(TString* output, const char* format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4) + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 31, "There were 5 substitution arguments given, but " "this format string is missing its $0-$4, contains one of " "$5-$9, or contains an unescaped $ character (use $$ instead)"); - + void SubstituteAndAppend(TString* output, const char* format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5) + const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 63, "There were 6 substitution arguments given, but " "this format string is missing its $0-$5, contains one of " "$6-$9, or contains an unescaped $ character (use $$ instead)"); - -void SubstituteAndAppend( + +void SubstituteAndAppend( TString* output, const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 127, "There were 7 substitution arguments given, but " "this format string is missing its $0-$6, contains one of " "$7-$9, or contains an unescaped $ character (use $$ instead)"); - -void SubstituteAndAppend( + +void SubstituteAndAppend( TString* output, const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7) + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 255, "There were 8 substitution arguments given, but " "this format string is missing its $0-$7, contains one of " "$8-$9, or contains an unescaped $ character (use $$ instead)"); - -void SubstituteAndAppend( + +void SubstituteAndAppend( TString* output, const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) - ABSL_BAD_CALL_IF( - substitute_internal::PlaceholderBitmask(format) != 511, - "There were 9 substitution arguments given, but " + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) + ABSL_BAD_CALL_IF( + substitute_internal::PlaceholderBitmask(format) != 511, + "There were 9 substitution arguments given, but " "this format string is missing its $0-$8, contains a $9, or " "contains an unescaped $ character (use $$ instead)"); - -void SubstituteAndAppend( + +void SubstituteAndAppend( TString* output, const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, - const substitute_internal::Arg& a9) + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, + const substitute_internal::Arg& a9) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 1023, "There were 10 substitution arguments given, but this " "format string either doesn't contain all of $0 through $9 or " "contains an unescaped $ character (use $$ instead)"); -#endif // ABSL_BAD_CALL_IF - -// Substitute() -// -// Substitutes variables into a given format string. See file comments above -// for usage. -// -// The declarations of `Substitute()` below consist of overloads for passing 0 -// to 10 arguments, respectively. -// -// NOTE: A zero-argument `Substitute()` may be used within variadic templates to -// allow a variable number of arguments. -// -// Example: -// template <typename... Args> +#endif // ABSL_BAD_CALL_IF + +// Substitute() +// +// Substitutes variables into a given format string. See file comments above +// for usage. +// +// The declarations of `Substitute()` below consist of overloads for passing 0 +// to 10 arguments, respectively. +// +// NOTE: A zero-argument `Substitute()` may be used within variadic templates to +// allow a variable number of arguments. +// +// Example: +// template <typename... Args> // void VarMsg(y_absl::string_view format, const Args&... args) { // TString s = y_absl::Substitute(format, args...); - + ABSL_MUST_USE_RESULT inline TString Substitute(y_absl::string_view format) { TString result; - SubstituteAndAppend(&result, format); - return result; -} - + SubstituteAndAppend(&result, format); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0) { TString result; - SubstituteAndAppend(&result, format, a0); - return result; -} - + SubstituteAndAppend(&result, format, a0); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1) { + const substitute_internal::Arg& a1) { TString result; - SubstituteAndAppend(&result, format, a0, a1); - return result; -} - + SubstituteAndAppend(&result, format, a0, a1); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) { + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) { TString result; - SubstituteAndAppend(&result, format, a0, a1, a2); - return result; -} - + SubstituteAndAppend(&result, format, a0, a1, a2); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3) { + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3) { TString result; - SubstituteAndAppend(&result, format, a0, a1, a2, a3); - return result; -} - + SubstituteAndAppend(&result, format, a0, a1, a2, a3); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) { + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) { TString result; - SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4); - return result; -} - + SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5) { + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5) { TString result; - SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5); - return result; -} - + SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) { + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) { TString result; - SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6); - return result; -} - + SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7) { + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7) { TString result; - SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7); - return result; -} - + SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) { + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) { TString result; - SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8); - return result; -} - + SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8); + return result; +} + ABSL_MUST_USE_RESULT inline TString Substitute( y_absl::string_view format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, - const substitute_internal::Arg& a9) { + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, + const substitute_internal::Arg& a9) { TString result; - SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); - return result; -} - -#if defined(ABSL_BAD_CALL_IF) -// This body of functions catches cases where the number of placeholders -// doesn't match the number of data arguments. + SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + return result; +} + +#if defined(ABSL_BAD_CALL_IF) +// This body of functions catches cases where the number of placeholders +// doesn't match the number of data arguments. TString Substitute(const char* format) - ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0, - "There were no substitution arguments " + ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0, + "There were no substitution arguments " "but this format string either has a $[0-9] in it or " "contains an unescaped $ character (use $$ instead)"); - + TString Substitute(const char* format, const substitute_internal::Arg& a0) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 1, "There was 1 substitution argument given, but " "this format string is missing its $0, contains one of $1-$9, " "or contains an unescaped $ character (use $$ instead)"); - + TString Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1) + const substitute_internal::Arg& a1) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 3, "There were 2 substitution arguments given, but " "this format string is missing its $0/$1, contains one of " "$2-$9, or contains an unescaped $ character (use $$ instead)"); - + TString Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 7, "There were 3 substitution arguments given, but " "this format string is missing its $0/$1/$2, contains one of " "$3-$9, or contains an unescaped $ character (use $$ instead)"); - + TString Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 15, "There were 4 substitution arguments given, but " "this format string is missing its $0-$3, contains one of " "$4-$9, or contains an unescaped $ character (use $$ instead)"); - + TString Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 31, "There were 5 substitution arguments given, but " "this format string is missing its $0-$4, contains one of " "$5-$9, or contains an unescaped $ character (use $$ instead)"); - + TString Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 63, "There were 6 substitution arguments given, but " "this format string is missing its $0-$5, contains one of " "$6-$9, or contains an unescaped $ character (use $$ instead)"); - + TString Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 127, "There were 7 substitution arguments given, but " "this format string is missing its $0-$6, contains one of " "$7-$9, or contains an unescaped $ character (use $$ instead)"); - + TString Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 255, "There were 8 substitution arguments given, but " "this format string is missing its $0-$7, contains one of " "$8-$9, or contains an unescaped $ character (use $$ instead)"); - + TString Substitute( - const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) - ABSL_BAD_CALL_IF( - substitute_internal::PlaceholderBitmask(format) != 511, - "There were 9 substitution arguments given, but " + const char* format, const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) + ABSL_BAD_CALL_IF( + substitute_internal::PlaceholderBitmask(format) != 511, + "There were 9 substitution arguments given, but " "this format string is missing its $0-$8, contains a $9, or " "contains an unescaped $ character (use $$ instead)"); - + TString Substitute( - const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, - const substitute_internal::Arg& a9) + const char* format, const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, + const substitute_internal::Arg& a9) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 1023, "There were 10 substitution arguments given, but this " "format string either doesn't contain all of $0 through $9 or " "contains an unescaped $ character (use $$ instead)"); -#endif // ABSL_BAD_CALL_IF - +#endif // ABSL_BAD_CALL_IF + ABSL_NAMESPACE_END } // namespace y_absl - -#endif // ABSL_STRINGS_SUBSTITUTE_H_ + +#endif // ABSL_STRINGS_SUBSTITUTE_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ya.make index 77c5a47dc9..d3abddfcee 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ya.make @@ -1,17 +1,17 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( somov g:cpp-contrib ) - -LICENSE(Apache-2.0) - + +LICENSE(Apache-2.0) + LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait @@ -19,28 +19,28 @@ PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity contrib/restricted/abseil-cpp-tstring/y_absl/numeric contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal -) - +) + ADDINCL( GLOBAL contrib/restricted/abseil-cpp-tstring ) - -NO_COMPILER_WARNINGS() - -SRCS( - ascii.cc - charconv.cc - escaping.cc - internal/charconv_bigint.cc - internal/charconv_parse.cc - internal/memutil.cc - match.cc - numbers.cc - str_cat.cc - str_replace.cc - str_split.cc - string_view.cc - substitute.cc -) - -END() + +NO_COMPILER_WARNINGS() + +SRCS( + ascii.cc + charconv.cc + escaping.cc + internal/charconv_bigint.cc + internal/charconv_parse.cc + internal/memutil.cc + match.cc + numbers.cc + str_cat.cc + str_replace.cc + str_split.cc + string_view.cc + substitute.cc +) + +END() |