diff options
Diffstat (limited to 'absl/strings')
97 files changed, 1572 insertions, 1274 deletions
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 3b85f1b4..20511a35 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -5,21 +5,20 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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. -# load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", - "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", "ABSL_EXCEPTIONS_FLAG_LINKOPTS", + "ABSL_TEST_COPTS", ) package( @@ -405,7 +404,7 @@ cc_test( cc_test( name = "numbers_test", - size = "small", + size = "medium", srcs = [ "internal/numbers_test_common.h", "numbers_test.cc", @@ -558,8 +557,8 @@ cc_library( visibility = ["//visibility:private"], deps = [ ":strings", + "//absl/base:config", "//absl/base:core_headers", - "//absl/container:inlined_vector", "//absl/meta:type_traits", "//absl/numeric:int128", "//absl/types:span", @@ -629,7 +628,7 @@ cc_test( cc_test( name = "str_format_convert_test", - size = "small", + size = "medium", srcs = ["internal/str_format/convert_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 5b877ad1..e63eec19 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,468 +14,507 @@ # limitations under the License. # - -list(APPEND STRINGS_PUBLIC_HEADERS - "ascii.h" - "charconv.h" - "escaping.h" - "match.h" - "numbers.h" - "str_cat.h" - "string_view.h" - "strip.h" - "str_join.h" - "str_replace.h" - "str_split.h" - "substitute.h" -) - - -list(APPEND STRINGS_INTERNAL_HEADERS - "internal/char_map.h" - "internal/charconv_bigint.h" - "internal/charconv_parse.h" - "internal/memutil.h" - "internal/ostringstream.h" - "internal/resize_uninitialized.h" - "internal/stl_type_traits.h" - "internal/str_join_internal.h" - "internal/str_split_internal.h" - "internal/utf8.h" -) - - - -# add string library -list(APPEND STRINGS_SRC - "ascii.cc" - "charconv.cc" - "escaping.cc" - "internal/charconv_bigint.cc" - "internal/charconv_parse.cc" - "internal/memutil.cc" - "internal/memutil.h" - "internal/utf8.cc" - "internal/ostringstream.cc" - "match.cc" - "numbers.cc" - "str_cat.cc" - "str_replace.cc" - "str_split.cc" - "string_view.cc" - "substitute.cc" - ${STRINGS_PUBLIC_HEADERS} - ${STRINGS_INTERNAL_HEADERS} -) -set(STRINGS_PUBLIC_LIBRARIES absl::base absl_internal_throw_delegate) - -absl_library( - TARGET - absl_strings - SOURCES - ${STRINGS_SRC} - PUBLIC_LIBRARIES - ${STRINGS_PUBLIC_LIBRARIES} - EXPORT_NAME +absl_cc_library( + NAME strings -) - -# add str_format library -absl_header_library( - TARGET - absl_str_format - PUBLIC_LIBRARIES - str_format_internal - EXPORT_NAME - str_format -) - -# str_format_internal -absl_library( - TARGET - str_format_internal - SOURCES - "internal/str_format/arg.cc" - "internal/str_format/bind.cc" - "internal/str_format/extension.cc" - "internal/str_format/float_conversion.cc" - "internal/str_format/output.cc" - "internal/str_format/parser.cc" - "internal/str_format/arg.h" - "internal/str_format/bind.h" - "internal/str_format/checker.h" - "internal/str_format/extension.h" - "internal/str_format/float_conversion.h" - "internal/str_format/output.h" - "internal/str_format/parser.h" - PUBLIC_LIBRARIES - str_format_extension_internal - absl::strings + HDRS + "ascii.h" + "charconv.h" + "escaping.h" + "match.h" + "numbers.h" + "str_cat.h" + "str_join.h" + "str_replace.h" + "str_split.h" + "string_view.h" + "strip.h" + "substitute.h" + SRCS + "ascii.cc" + "charconv.cc" + "escaping.cc" + "internal/charconv_bigint.cc" + "internal/charconv_bigint.h" + "internal/charconv_parse.cc" + "internal/charconv_parse.h" + "internal/memutil.cc" + "internal/memutil.h" + "internal/stl_type_traits.h" + "internal/str_join_internal.h" + "internal/str_split_internal.h" + "match.cc" + "numbers.cc" + "str_cat.cc" + "str_replace.cc" + "str_split.cc" + "string_view.cc" + "substitute.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::strings_internal absl::base - absl::numeric - absl::inlined_vector - absl::span -) - -# str_format_extension_internal -absl_library( - TARGET - str_format_extension_internal - SOURCES - "internal/str_format/extension.cc" - "internal/str_format/extension.h" - "internal/str_format/output.cc" - "internal/str_format/output.h" - PUBLIC_LIBRARIES - absl::base - absl::strings -) - -# pow10_helper -absl_library( - TARGET - pow10_helper - SOURCES - "internal/pow10_helper.cc" - "internal/pow10_helper.h" -) - -# -## TESTS -# - -# test match_test -set(MATCH_TEST_SRC "match_test.cc") -set(MATCH_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET + absl::bits + absl::config + absl::core_headers + absl::endian + absl::throw_delegate + absl::memory + absl::type_traits + absl::int128 + PUBLIC +) + +absl_cc_library( + NAME + strings_internal + HDRS + "internal/char_map.h" + "internal/ostringstream.h" + "internal/resize_uninitialized.h" + "internal/utf8.h" + SRCS + "internal/ostringstream.cc" + "internal/utf8.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::endian + absl::type_traits +) + +absl_cc_test( + NAME match_test - SOURCES - ${MATCH_TEST_SRC} - PUBLIC_LIBRARIES - ${MATCH_TEST_PUBLIC_LIBRARIES} + SRCS + "match_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + gmock_main ) - -# test escaping_test -set(ESCAPING_TEST_SRC "escaping_test.cc") -set(ESCAPING_TEST_PUBLIC_LIBRARIES absl::strings absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME escaping_test - SOURCES - ${ESCAPING_TEST_SRC} - PUBLIC_LIBRARIES - ${ESCAPING_TEST_PUBLIC_LIBRARIES} + SRCS + "escaping_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + absl::fixed_array + gmock_main ) - -# test ascii_test -set(ASCII_TEST_SRC "ascii_test.cc") -set(ASCII_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET +absl_cc_test( + NAME ascii_test - SOURCES - ${ASCII_TEST_SRC} - PUBLIC_LIBRARIES - ${ASCII_TEST_PUBLIC_LIBRARIES} + SRCS + "ascii_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + gmock_main ) - -# test memutil_test -set(MEMUTIL_TEST_SRC "internal/memutil_test.cc") -set(MEMUTIL_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET +absl_cc_test( + NAME memutil_test - SOURCES - ${MEMUTIL_TEST_SRC} - PUBLIC_LIBRARIES - ${MEMUTIL_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/memutil.h" + "internal/memutil_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + gmock_main ) - -# test utf8_test -set(UTF8_TEST_SRC "internal/utf8_test.cc") -set(UTF8_TEST_PUBLIC_LIBRARIES absl::strings absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME utf8_test - SOURCES - ${UTF8_TEST_SRC} - PUBLIC_LIBRARIES - ${UTF8_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/utf8_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings_internal + absl::base + absl::core_headers + gmock_main ) - -# test string_view_test -set(STRING_VIEW_TEST_SRC "string_view_test.cc") -set(STRING_VIEW_TEST_PUBLIC_LIBRARIES absl::strings absl_internal_throw_delegate absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME string_view_test - SOURCES - ${STRING_VIEW_TEST_SRC} - PUBLIC_LIBRARIES - ${STRING_VIEW_TEST_PUBLIC_LIBRARIES} + SRCS + "string_view_test.cc" + COPTS + ${ABSL_TEST_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::strings + absl::config + absl::core_headers + absl::dynamic_annotations + gmock_main ) - -# test substitute_test -set(SUBSTITUTE_TEST_SRC "substitute_test.cc") -set(SUBSTITUTE_TEST_PUBLIC_LIBRARIES absl::strings absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME substitute_test - SOURCES - ${SUBSTITUTE_TEST_SRC} - PUBLIC_LIBRARIES - ${SUBSTITUTE_TEST_PUBLIC_LIBRARIES} + SRCS + "substitute_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + gmock_main ) - -# test str_replace_test -set(STR_REPLACE_TEST_SRC "str_replace_test.cc") -set(STR_REPLACE_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_internal_throw_delegate) - -absl_test( - TARGET +absl_cc_test( + NAME str_replace_test - SOURCES - ${STR_REPLACE_TEST_SRC} - PUBLIC_LIBRARIES - ${STR_REPLACE_TEST_PUBLIC_LIBRARIES} + SRCS + "str_replace_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + gmock_main ) - -# test str_split_test -set(STR_SPLIT_TEST_SRC "str_split_test.cc") -set(STR_SPLIT_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_internal_throw_delegate) - -absl_test( - TARGET +absl_cc_test( + NAME str_split_test - SOURCES - ${STR_SPLIT_TEST_SRC} - PUBLIC_LIBRARIES - ${STR_SPLIT_TEST_PUBLIC_LIBRARIES} + SRCS + "str_split_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + absl::core_headers + absl::dynamic_annotations + gmock_main ) - -# test ostringstream_test -set(OSTRINGSTREAM_TEST_SRC "internal/ostringstream_test.cc") -set(OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET +absl_cc_test( + NAME ostringstream_test - SOURCES - ${OSTRINGSTREAM_TEST_SRC} - PUBLIC_LIBRARIES - ${OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/ostringstream_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings_internal + gmock_main ) - -# test resize_uninitialized_test -set(RESIZE_UNINITIALIZED_TEST_SRC "internal/resize_uninitialized_test.cc") - -absl_test( - TARGET +absl_cc_test( + NAME resize_uninitialized_test - SOURCES - ${RESIZE_UNINITIALIZED_TEST_SRC} + SRCS + "internal/resize_uninitialized.h" + "internal/resize_uninitialized_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::core_headers + absl::type_traits + gmock_main ) - -# test str_join_test -set(STR_JOIN_TEST_SRC "str_join_test.cc") -set(STR_JOIN_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET +absl_cc_test( + NAME str_join_test - SOURCES - ${STR_JOIN_TEST_SRC} - PUBLIC_LIBRARIES - ${STR_JOIN_TEST_PUBLIC_LIBRARIES} + SRCS + "str_join_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + absl::core_headers + absl::memory + gmock_main ) - -# test str_cat_test -set(STR_CAT_TEST_SRC "str_cat_test.cc") -set(STR_CAT_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET +absl_cc_test( + NAME str_cat_test - SOURCES - ${STR_CAT_TEST_SRC} - PUBLIC_LIBRARIES - ${STR_CAT_TEST_PUBLIC_LIBRARIES} + SRCS + "str_cat_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + gmock_main ) - -# test numbers_test -set(NUMBERS_TEST_SRC "numbers_test.cc") -set(NUMBERS_TEST_PUBLIC_LIBRARIES absl::strings pow10_helper) - -absl_test( - TARGET +absl_cc_test( + NAME numbers_test - SOURCES - ${NUMBERS_TEST_SRC} - PUBLIC_LIBRARIES - ${NUMBERS_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/numbers_test_common.h" + "numbers_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + absl::core_headers + absl::pow10_helper + gmock_main ) - -# test strip_test -set(STRIP_TEST_SRC "strip_test.cc") -set(STRIP_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET +absl_cc_test( + NAME strip_test - SOURCES - ${STRIP_TEST_SRC} - PUBLIC_LIBRARIES - ${STRIP_TEST_PUBLIC_LIBRARIES} + SRCS + "strip_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + gmock_main ) - -# test char_map_test -set(CHAR_MAP_TEST_SRC "internal/char_map_test.cc") -set(CHAR_MAP_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET +absl_cc_test( + NAME char_map_test - SOURCES - ${CHAR_MAP_TEST_SRC} - PUBLIC_LIBRARIES - ${CHAR_MAP_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/char_map_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings_internal + gmock_main ) - -# test charconv_test -set(CHARCONV_TEST_SRC "charconv_test.cc") -set(CHARCONV_TEST_PUBLIC_LIBRARIES absl::strings absl::str_format pow10_helper) - -absl_test( - TARGET +absl_cc_test( + NAME charconv_test - SOURCES - ${CHARCONV_TEST_SRC} - PUBLIC_LIBRARIES - ${CHARCONV_TEST_PUBLIC_LIBRARIES} + SRCS + "charconv_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::str_format + absl::base + absl::pow10_helper + gmock_main ) - -# test charconv_parse_test -set(CHARCONV_PARSE_TEST_SRC "internal/charconv_parse_test.cc") -set(CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET +absl_cc_test( + NAME charconv_parse_test - SOURCES - ${CHARCONV_PARSE_TEST_SRC} - PUBLIC_LIBRARIES - ${CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/charconv_parse.h" + "internal/charconv_parse_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + gmock_main ) +absl_cc_test( + NAME + charconv_bigint_test + SRCS + "internal/charconv_bigint.h" + "internal/charconv_bigint_test.cc" + "internal/charconv_parse.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + gmock_main +) -# test charconv_bigint_test -set(CHARCONV_BIGINT_TEST_SRC "internal/charconv_bigint_test.cc") -set(CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES absl::strings) +absl_cc_library( + NAME + str_format + HDRS + "str_format.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::str_format_internal + PUBLIC +) -absl_test( - TARGET - charconv_bigint_test - SOURCES - ${CHARCONV_BIGINT_TEST_SRC} - PUBLIC_LIBRARIES - ${CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES} -) -# test str_format_test -absl_test( - TARGET +absl_cc_library( + NAME + str_format_internal + HDRS + "internal/str_format/arg.h" + "internal/str_format/bind.h" + "internal/str_format/checker.h" + "internal/str_format/extension.h" + "internal/str_format/float_conversion.h" + "internal/str_format/output.h" + "internal/str_format/parser.h" + SRCS + "internal/str_format/arg.cc" + "internal/str_format/bind.cc" + "internal/str_format/extension.cc" + "internal/str_format/float_conversion.cc" + "internal/str_format/output.cc" + "internal/str_format/parser.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::strings + absl::config + absl::core_headers + absl::type_traits + absl::int128 + absl::span +) + +absl_cc_test( + NAME str_format_test - SOURCES + SRCS "str_format_test.cc" - PUBLIC_LIBRARIES - absl::base + COPTS + ${ABSL_TEST_COPTS} + DEPS absl::str_format absl::strings + absl::core_headers + gmock_main +) + +absl_cc_test( + NAME + str_format_extension_test + SRCS + "internal/str_format/extension_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format + absl::str_format_internal + gmock_main +) + +absl_cc_test( + NAME + str_format_arg_test + SRCS + "internal/str_format/arg_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format + absl::str_format_internal + gmock_main ) -# test str_format_bind_test -absl_test( - TARGET +absl_cc_test( + NAME str_format_bind_test - SOURCES + SRCS "internal/str_format/bind_test.cc" - PUBLIC_LIBRARIES - str_format_internal + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format_internal + gmock_main ) -# test str_format_checker_test -absl_test( - TARGET +absl_cc_test( + NAME str_format_checker_test - SOURCES + SRCS "internal/str_format/checker_test.cc" - PUBLIC_LIBRARIES + COPTS + ${ABSL_TEST_COPTS} + DEPS absl::str_format + gmock_main ) -# test str_format_convert_test -absl_test( - TARGET +absl_cc_test( + NAME str_format_convert_test - SOURCES + SRCS "internal/str_format/convert_test.cc" - PUBLIC_LIBRARIES - str_format_internal - absl::numeric + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format_internal + absl::int128 + gmock_main ) -# test str_format_output_test -absl_test( - TARGET +absl_cc_test( + NAME str_format_output_test - SOURCES + SRCS "internal/str_format/output_test.cc" - PUBLIC_LIBRARIES - str_format_extension_internal + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format_internal + gmock_main ) -# test str_format_parser_test -absl_test( - TARGET +absl_cc_test( + NAME str_format_parser_test - SOURCES + SRCS "internal/str_format/parser_test.cc" - PUBLIC_LIBRARIES - str_format_internal - absl::base + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format_internal + absl::core_headers + gmock_main +) + +absl_cc_library( + NAME + pow10_helper + HDRS + "internal/pow10_helper.h" + SRCS + "internal/pow10_helper.cc" + COPTS + ${ABSL_TEST_COPTS} + TESTONLY ) -# test pow10_helper_test -absl_test( - TARGET +absl_cc_test( + NAME pow10_helper_test - SOURCES + SRCS "internal/pow10_helper_test.cc" - PUBLIC_LIBRARIES - pow10_helper + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::pow10_helper absl::str_format + gmock_main ) diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc index 5d08e816..045a5e21 100644 --- a/absl/strings/ascii.cc +++ b/absl/strings/ascii.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -15,7 +15,7 @@ #include "absl/strings/ascii.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace ascii_internal { // # Table generated by this Python code (bit 0x02 is currently unused): @@ -196,5 +196,5 @@ void RemoveExtraAsciiWhitespace(std::string* str) { str->erase(output_it - &(*str)[0]); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h index 98418fd2..ebcbb11a 100644 --- a/absl/strings/ascii.h +++ b/absl/strings/ascii.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -59,7 +59,7 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace ascii_internal { // Declaration for an array of bitfields holding character information. @@ -235,7 +235,7 @@ inline void StripAsciiWhitespace(std::string* str) { // Removes leading, trailing, and consecutive internal whitespace. void RemoveExtraAsciiWhitespace(std::string*); -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_ASCII_H_ diff --git a/absl/strings/ascii_benchmark.cc b/absl/strings/ascii_benchmark.cc index 8dea4b8c..aca458c8 100644 --- a/absl/strings/ascii_benchmark.cc +++ b/absl/strings/ascii_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc index 9903b049..5ecd23f8 100644 --- a/absl/strings/ascii_test.cc +++ b/absl/strings/ascii_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc index 21ea17b1..866a163e 100644 --- a/absl/strings/charconv.cc +++ b/absl/strings/charconv.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -57,7 +57,7 @@ // narrower mantissas. namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace { template <typename FloatType> @@ -552,9 +552,10 @@ CalculatedFloat CalculateFromParsedDecimal( 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 charconv_algorithm.md. - // They represent the number of bits in `wide_binary_mantissa` that are - // guaranteed to be unaffected by error propagation. + // `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) { @@ -980,5 +981,5 @@ const int16_t kPower10ExponentTable[] = { }; } // namespace -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h index 160306e6..0b84ccac 100644 --- a/absl/strings/charconv.h +++ b/absl/strings/charconv.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,7 +18,7 @@ #include <system_error> // NOLINT(build/c++11) namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // Workalike compatibilty version of std::chars_format from C++17. // @@ -50,9 +50,9 @@ struct from_chars_result { // this only supports the `double` and `float` types. // // This interface incorporates the proposed resolutions for library issues -// DR 3800 and DR 3801. If these are adopted with different wording, +// 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 3801, which says what `value` will be set to in +// 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.) @@ -111,7 +111,7 @@ inline chars_format& operator^=(chars_format& lhs, chars_format rhs) { return lhs; } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_CHARCONV_H_ diff --git a/absl/strings/charconv_benchmark.cc b/absl/strings/charconv_benchmark.cc index fd83f44e..644b2abd 100644 --- a/absl/strings/charconv_benchmark.cc +++ b/absl/strings/charconv_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc index d07537eb..b58fad26 100644 --- a/absl/strings/charconv_test.cc +++ b/absl/strings/charconv_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -279,7 +279,8 @@ void TestHalfwayValue(const std::string& mantissa, int exponent, absl::from_chars(low_rep.data(), low_rep.data() + low_rep.size(), actual_low); EXPECT_EQ(expected_low, actual_low); - std::string high_rep = absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent); + std::string high_rep = + absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent); FloatType actual_high = 0; absl::from_chars(high_rep.data(), high_rep.data() + high_rep.size(), actual_high); diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc index 69053c19..eb0974dc 100644 --- a/absl/strings/escaping.cc +++ b/absl/strings/escaping.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -33,7 +33,7 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace { // Digit conversion. @@ -180,7 +180,8 @@ bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped, ch = (ch << 4) + hex_digit_to_int(*++p); if (ch > 0xFF) { if (error) { - *error = "Value of \\" + std::string(hex_start, p + 1 - hex_start) + + *error = "Value of \\" + + std::string(hex_start, p + 1 - hex_start) + " exceeds 0xff"; } return false; @@ -295,7 +296,7 @@ bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped, // ---------------------------------------------------------------------- // CUnescapeInternal() // -// Same as above but uses a C++ string for output. 'source' and 'dest' +// Same as above but uses a std::string for output. 'source' and 'dest' // may be the same. // ---------------------------------------------------------------------- bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped, @@ -325,7 +326,8 @@ bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped, // // Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint(). // ---------------------------------------------------------------------- -std::string CEscapeInternal(absl::string_view src, bool use_hex, bool utf8_safe) { +std::string CEscapeInternal(absl::string_view src, bool use_hex, + bool utf8_safe) { std::string dest; bool last_hex_escape = false; // true if last output char was \xNN. @@ -787,7 +789,7 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { // Base64 encodes three bytes of input at a time. If the input is not // divisible by three, we pad as appropriate. // - // (from http://tools.ietf.org/html/rfc3548) + // (from https://tools.ietf.org/html/rfc3548) // Special processing is performed if fewer than 24 bits are available // at the end of the data being encoded. A full encoding quantum is // always completed at the end of a quantity. When fewer than 24 input @@ -801,12 +803,12 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { size_t len = (input_len / 3) * 4; if (input_len % 3 == 0) { - // (from http://tools.ietf.org/html/rfc3548) + // (from https://tools.ietf.org/html/rfc3548) // (1) the final quantum of encoding input is an integral multiple of 24 // bits; here, the final unit of encoded output will be an integral // multiple of 4 characters with no "=" padding, } else if (input_len % 3 == 1) { - // (from http://tools.ietf.org/html/rfc3548) + // (from https://tools.ietf.org/html/rfc3548) // (2) the final quantum of encoding input is exactly 8 bits; here, the // final unit of encoded output will be two characters followed by two // "=" padding characters, or @@ -815,7 +817,7 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { len += 2; } } else { // (input_len % 3 == 2) - // (from http://tools.ietf.org/html/rfc3548) + // (from https://tools.ietf.org/html/rfc3548) // (3) the final quantum of encoding input is exactly 16 bits; here, the // final unit of encoded output will be three characters followed by one // "=" padding character. @@ -844,8 +846,8 @@ size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest, // Three bytes of data encodes to four characters of cyphertext. // So we can pump through three-byte chunks atomically. - if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3 - while (cur_src < limit_src - 3) { // as long as we have >= 32 bits + if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3. + while (cur_src < limit_src - 3) { // While we have >= 32 bits. uint32_t in = absl::big_endian::Load32(cur_src) >> 8; cur_dest[0] = base64[in >> 18]; @@ -1012,7 +1014,8 @@ void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) { } } -// This is a templated function so that T can be either a char* or a string. +// This is a templated function so that T can be either a char* or a +// std::string. template <typename T> void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) { auto dest_ptr = &dest[0]; @@ -1029,7 +1032,8 @@ void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) { // // See CUnescapeInternal() for implementation details. // ---------------------------------------------------------------------- -bool CUnescape(absl::string_view source, std::string* dest, std::string* error) { +bool CUnescape(absl::string_view source, std::string* dest, + std::string* error) { return CUnescapeInternal(source, kUnescapeNulls, dest, error); } @@ -1052,10 +1056,10 @@ std::string Utf8SafeCHexEscape(absl::string_view src) { } // ---------------------------------------------------------------------- -// ptrdiff_t Base64Unescape() - base64 decoder -// ptrdiff_t Base64Escape() - base64 encoder -// ptrdiff_t WebSafeBase64Unescape() - Google's variation of base64 decoder -// ptrdiff_t WebSafeBase64Escape() - Google's variation of base64 encoder +// 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 @@ -1093,6 +1097,20 @@ void WebSafeBase64Escape(absl::string_view src, std::string* dest) { src.size(), dest, false, kWebSafeBase64Chars); } +std::string Base64Escape(absl::string_view src) { + std::string dest; + Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()), + src.size(), &dest, true, kBase64Chars); + return dest; +} + +std::string WebSafeBase64Escape(absl::string_view src) { + std::string dest; + Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()), + src.size(), &dest, false, kWebSafeBase64Chars); + return dest; +} + std::string HexStringToBytes(absl::string_view from) { std::string result; const auto num = from.size() / 2; @@ -1109,5 +1127,5 @@ std::string BytesToHexString(absl::string_view from) { return result; } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h index a31fb374..7f1c5d46 100644 --- a/absl/strings/escaping.h +++ b/absl/strings/escaping.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -19,7 +19,6 @@ // // 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_ @@ -34,12 +33,12 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // CUnescape() // // Unescapes a `source` string and copies it into `dest`, rewriting C-style -// escape sequences (http://en.cppreference.com/w/cpp/language/escape) into +// 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: @@ -57,7 +56,6 @@ inline namespace lts_2018_12_18 { // 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 @@ -81,7 +79,7 @@ inline bool CUnescape(absl::string_view source, std::string* dest) { // CEscape() // // Escapes a 'src' string using C-style escapes sequences -// (http://en.cppreference.com/w/cpp/language/escape), escaping other +// (https://en.cppreference.com/w/cpp/language/escape), escaping other // non-printable/non-whitespace bytes as octal sequences (e.g. "\377"). // // Example: @@ -135,16 +133,18 @@ bool WebSafeBase64Unescape(absl::string_view src, std::string* dest); // Base64Escape() // -// Encodes a `src` string into a `dest` buffer using base64 encoding, with -// padding characters. This function conforms with RFC 4648 section 4 (base64). +// Encodes a `src` string into a base64-encoded string, with padding characters. +// This function conforms with RFC 4648 section 4 (base64). void Base64Escape(absl::string_view src, std::string* dest); +std::string Base64Escape(absl::string_view src); // WebSafeBase64Escape() // -// Encodes a `src` string into a `dest` buffer using '-' instead of '+' and -// '_' instead of '/', and without padding. This function conforms with RFC 4648 -// section 5 (base64url). +// 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(absl::string_view src, std::string* dest); +std::string WebSafeBase64Escape(absl::string_view src); // HexStringToBytes() // @@ -158,7 +158,7 @@ std::string HexStringToBytes(absl::string_view from); // `2*from.size()`. std::string BytesToHexString(absl::string_view from); -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_ESCAPING_H_ diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc index 0f791f4e..10d5b033 100644 --- a/absl/strings/escaping_benchmark.cc +++ b/absl/strings/escaping_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc index 9dc27f3f..1967975b 100644 --- a/absl/strings/escaping_test.cc +++ b/absl/strings/escaping_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -36,18 +36,19 @@ struct epair { TEST(CEscape, EscapeAndUnescape) { const std::string inputs[] = { - std::string("foo\nxx\r\b\0023"), - std::string(""), - std::string("abc"), - std::string("\1chad_rules"), - std::string("\1arnar_drools"), - std::string("xxxx\r\t'\"\\"), - std::string("\0xx\0", 4), - std::string("\x01\x31"), - std::string("abc\xb\x42\141bc"), - std::string("123\1\x31\x32\x33"), - std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"), - std::string("\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"), + std::string("foo\nxx\r\b\0023"), + std::string(""), + std::string("abc"), + std::string("\1chad_rules"), + std::string("\1arnar_drools"), + std::string("xxxx\r\t'\"\\"), + std::string("\0xx\0", 4), + std::string("\x01\x31"), + std::string("abc\xb\x42\141bc"), + std::string("123\1\x31\x32\x33"), + std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"), + std::string( + "\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"), }; // Do this twice, once for octal escapes and once for hex escapes. for (int kind = 0; kind < 4; kind++) { @@ -71,6 +72,11 @@ TEST(CEscape, EscapeAndUnescape) { EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str)); EXPECT_EQ(unescaped_str, original); + unescaped_str.erase(); + std::string error; + EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str, &error)); + EXPECT_EQ(error, ""); + // Check in-place unescaping std::string s = escaped; EXPECT_TRUE(absl::CUnescape(s, &s)); @@ -149,7 +155,8 @@ TEST(CEscape, BasicEscaping) { TEST(Unescape, BasicFunction) { epair tests[] = - {{"\\u0030", "0"}, + {{"", ""}, + {"\\u0030", "0"}, {"\\u00A3", "\xC2\xA3"}, {"\\u22FD", "\xE2\x8B\xBD"}, {"\\U00010000", "\xF0\x90\x80\x80"}, @@ -159,20 +166,22 @@ TEST(Unescape, BasicFunction) { EXPECT_TRUE(absl::CUnescape(val.escaped, &out)); EXPECT_EQ(out, val.unescaped); } - std::string bad[] = - {"\\u1", // too short - "\\U1", // too short - "\\Uffffff", // exceeds 0x10ffff (largest Unicode) - "\\U00110000", // exceeds 0x10ffff (largest Unicode) - "\\uD835", // surrogate character (D800-DFFF) - "\\U0000DD04", // surrogate character (D800-DFFF) - "\\777", // exceeds 0xff - "\\xABCD"}; // exceeds 0xff + std::string bad[] = {"\\u1", // too short + "\\U1", // too short + "\\Uffffff", // exceeds 0x10ffff (largest Unicode) + "\\U00110000", // exceeds 0x10ffff (largest Unicode) + "\\uD835", // surrogate character (D800-DFFF) + "\\U0000DD04", // surrogate character (D800-DFFF) + "\\777", // exceeds 0xff + "\\xABCD"}; // exceeds 0xff for (const std::string& e : bad) { std::string error; std::string out; EXPECT_FALSE(absl::CUnescape(e, &out, &error)); EXPECT_FALSE(error.empty()); + + out.erase(); + EXPECT_FALSE(absl::CUnescape(e, &out)); } } @@ -258,9 +267,11 @@ TEST_F(CUnescapeTest, UnescapesMultipleOctalNulls) { // All escapes, including newlines and null escapes, should have been // converted to the equivalent characters. EXPECT_EQ(std::string("\0\n" - "0\n" - "\0\n" - "\0", 7), result_string_); + "0\n" + "\0\n" + "\0", + 7), + result_string_); } @@ -268,17 +279,21 @@ TEST_F(CUnescapeTest, UnescapesMultipleHexNulls) { std::string original_string(kStringWithMultipleHexNulls); EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); EXPECT_EQ(std::string("\0\n" - "0\n" - "\0\n" - "\0", 7), result_string_); + "0\n" + "\0\n" + "\0", + 7), + result_string_); } TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) { std::string original_string(kStringWithMultipleUnicodeNulls); EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); EXPECT_EQ(std::string("\0\n" - "0\n" - "\0", 5), result_string_); + "0\n" + "\0", + 5), + result_string_); } static struct { @@ -550,6 +565,7 @@ void TestEscapeAndUnescape() { StringType encoded("this junk should be ignored"); absl::Base64Escape(tc.plaintext, &encoded); EXPECT_EQ(encoded, tc.cyphertext); + EXPECT_EQ(absl::Base64Escape(tc.plaintext), tc.cyphertext); StringType decoded("this junk should be ignored"); EXPECT_TRUE(absl::Base64Unescape(encoded, &decoded)); @@ -568,6 +584,7 @@ void TestEscapeAndUnescape() { encoded = "this junk should be ignored"; absl::WebSafeBase64Escape(tc.plaintext, &encoded); EXPECT_EQ(encoded, websafe); + EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), websafe); // Let's try the std::string version of the decoder decoded = "this junk should be ignored"; @@ -580,6 +597,7 @@ void TestEscapeAndUnescape() { StringType buffer; absl::WebSafeBase64Escape(tc.plaintext, &buffer); EXPECT_EQ(tc.cyphertext, buffer); + EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), tc.cyphertext); } // Verify the behavior when decoding bad data diff --git a/absl/strings/internal/char_map.h b/absl/strings/internal/char_map.h index 10b7d007..772ae869 100644 --- a/absl/strings/internal/char_map.h +++ b/absl/strings/internal/char_map.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -28,7 +28,7 @@ #include "absl/base/port.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { class Charmap { @@ -150,7 +150,7 @@ constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); } constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ diff --git a/absl/strings/internal/char_map_benchmark.cc b/absl/strings/internal/char_map_benchmark.cc index c45f3157..5cef967b 100644 --- a/absl/strings/internal/char_map_benchmark.cc +++ b/absl/strings/internal/char_map_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/internal/char_map_test.cc b/absl/strings/internal/char_map_test.cc index c3601e10..d3306241 100644 --- a/absl/strings/internal/char_map_test.cc +++ b/absl/strings/internal/char_map_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc index dac907e2..58c909f4 100644 --- a/absl/strings/internal/charconv_bigint.cc +++ b/absl/strings/internal/charconv_bigint.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -19,7 +19,7 @@ #include <string> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { namespace { @@ -355,5 +355,5 @@ template class BigUnsigned<4>; template class BigUnsigned<84>; } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/charconv_bigint.h b/absl/strings/internal/charconv_bigint.h index ffafc11c..5aef416b 100644 --- a/absl/strings/internal/charconv_bigint.h +++ b/absl/strings/internal/charconv_bigint.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -25,7 +25,7 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { // The largest power that 5 that can be raised to, and still fit in a uint32_t. @@ -104,12 +104,12 @@ class BigUnsigned { SetToZero(); return; } - size_ = std::min(size_ + word_shift, max_words); + 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) { + 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)); } @@ -268,7 +268,7 @@ class BigUnsigned { 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); + (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); } @@ -287,7 +287,7 @@ class BigUnsigned { value = 0; } } - size_ = std::min(max_words, std::max(index + 1, size_)); + size_ = (std::min)(max_words, (std::max)(index + 1, size_)); } } @@ -310,7 +310,7 @@ class BigUnsigned { } 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_)); + size_ = (std::min)(max_words, (std::max)(index + 1, size_)); } } } @@ -349,7 +349,7 @@ class BigUnsigned { // 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()); + 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); @@ -364,7 +364,7 @@ int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { template <int N, int M> bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - int limit = std::max(lhs.size(), rhs.size()); + int limit = (std::max)(lhs.size(), rhs.size()); for (int i = 0; i < limit; ++i) { if (lhs.GetWord(i) != rhs.GetWord(i)) { return false; @@ -415,7 +415,7 @@ extern template class BigUnsigned<4>; extern template class BigUnsigned<84>; } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ diff --git a/absl/strings/internal/charconv_bigint_test.cc b/absl/strings/internal/charconv_bigint_test.cc index dbab3208..590511d0 100644 --- a/absl/strings/internal/charconv_bigint_test.cc +++ b/absl/strings/internal/charconv_bigint_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -19,7 +19,7 @@ #include "gtest/gtest.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { TEST(BigUnsigned, ShiftLeft) { @@ -201,5 +201,5 @@ TEST(BigUnsigned, TenToTheNth) { } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc index 68d65a8a..4dd4ecb3 100644 --- a/absl/strings/internal/charconv_parse.cc +++ b/absl/strings/internal/charconv_parse.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -22,7 +22,7 @@ #include "absl/strings/internal/memutil.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace { // ParseFloat<10> will read the first 19 significant digits of the mantissa. @@ -494,5 +494,5 @@ template ParsedFloat ParseFloat<16>(const char* begin, const char* end, chars_format format_flags); } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/charconv_parse.h b/absl/strings/internal/charconv_parse.h index 17d5a8f8..ddfc87f8 100644 --- a/absl/strings/internal/charconv_parse.h +++ b/absl/strings/internal/charconv_parse.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,7 +20,7 @@ #include "absl/strings/charconv.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { // Enum indicating whether a parsed float is a number or special value. @@ -93,6 +93,6 @@ extern template ParsedFloat ParseFloat<16>(const char* begin, const char* end, absl::chars_format format_flags); } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ diff --git a/absl/strings/internal/charconv_parse_test.cc b/absl/strings/internal/charconv_parse_test.cc index f48b9aee..9511c987 100644 --- a/absl/strings/internal/charconv_parse_test.cc +++ b/absl/strings/internal/charconv_parse_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/internal/escaping_test_common.h b/absl/strings/internal/escaping_test_common.h index 50ef595f..ecd3aa35 100644 --- a/absl/strings/internal/escaping_test_common.h +++ b/absl/strings/internal/escaping_test_common.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -22,7 +22,7 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { struct base64_testcase { @@ -127,7 +127,7 @@ inline const std::array<base64_testcase, 5>& base64_strings() { } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ diff --git a/absl/strings/internal/memutil.cc b/absl/strings/internal/memutil.cc index 1d6cfa36..05251377 100644 --- a/absl/strings/internal/memutil.cc +++ b/absl/strings/internal/memutil.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,7 +17,7 @@ #include <cstdlib> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { int memcasecmp(const char* s1, const char* s2, size_t len) { @@ -108,5 +108,5 @@ const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/memutil.h b/absl/strings/internal/memutil.h index dcc5c9a3..4efac989 100644 --- a/absl/strings/internal/memutil.h +++ b/absl/strings/internal/memutil.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -69,7 +69,7 @@ #include "absl/strings/ascii.h" // for absl::ascii_tolower namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { inline char* memcat(char* dest, size_t destlen, const char* src, @@ -142,7 +142,7 @@ const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, size_t neelen); } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_MEMUTIL_H_ diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc index 77915adb..dc95c3e5 100644 --- a/absl/strings/internal/memutil_benchmark.cc +++ b/absl/strings/internal/memutil_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/internal/memutil_test.cc b/absl/strings/internal/memutil_test.cc index 09424de9..d8681ddf 100644 --- a/absl/strings/internal/memutil_test.cc +++ b/absl/strings/internal/memutil_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/internal/numbers_test_common.h b/absl/strings/internal/numbers_test_common.h index 32aa0bfa..3f6965f2 100644 --- a/absl/strings/internal/numbers_test_common.h +++ b/absl/strings/internal/numbers_test_common.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -24,7 +24,7 @@ #include <string> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { template <typename IntType> @@ -175,7 +175,7 @@ inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() { } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ diff --git a/absl/strings/internal/ostringstream.cc b/absl/strings/internal/ostringstream.cc index 77f4b0b3..ce2dd6c7 100644 --- a/absl/strings/internal/ostringstream.cc +++ b/absl/strings/internal/ostringstream.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -15,7 +15,7 @@ #include "absl/strings/internal/ostringstream.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { OStringStream::Buf::int_type OStringStream::overflow(int c) { @@ -32,5 +32,5 @@ std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) { } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/ostringstream.h b/absl/strings/internal/ostringstream.h index 908e170c..2cf65133 100644 --- a/absl/strings/internal/ostringstream.h +++ b/absl/strings/internal/ostringstream.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -23,21 +23,21 @@ #include "absl/base/port.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { -// The same as std::ostringstream but appends to a user-specified string, +// The same as std::ostringstream but appends to a user-specified std::string, // and is faster. It is ~70% faster to create, ~50% faster to write to, and -// completely free to extract the result string. +// completely free to extract the result std::string. // -// string s; +// std::string 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. // -// string s; +// std::string s; // OStringStream(&s) << 42 << ' ' << 3.14; // appends to `s` // // OStringStream is faster to create than std::ostringstream but it's still @@ -46,14 +46,14 @@ namespace strings_internal { // // Creates unnecessary instances of OStringStream: slow. // -// string s; +// std::string s; // OStringStream(&s) << 42; // OStringStream(&s) << ' '; // OStringStream(&s) << 3.14; // // Creates a single instance of OStringStream and reuses it: fast. // -// string s; +// std::string s; // OStringStream strm(&s); // strm << 42; // strm << ' '; @@ -65,8 +65,8 @@ class OStringStream : private std::basic_streambuf<char>, public std::ostream { // 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 std::string. It's OK to destroy - // the std::string before the stream. + // The destructor of OStringStream doesn't use the std::string. It's OK to + // destroy the std::string before the stream. explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {} std::string* str() { return s_; } @@ -83,7 +83,7 @@ class OStringStream : private std::basic_streambuf<char>, public std::ostream { }; } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ diff --git a/absl/strings/internal/ostringstream_benchmark.cc b/absl/strings/internal/ostringstream_benchmark.cc index c93f9690..5979f182 100644 --- a/absl/strings/internal/ostringstream_benchmark.cc +++ b/absl/strings/internal/ostringstream_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/internal/ostringstream_test.cc b/absl/strings/internal/ostringstream_test.cc index 069a0e1f..2879e50e 100644 --- a/absl/strings/internal/ostringstream_test.cc +++ b/absl/strings/internal/ostringstream_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/internal/pow10_helper.cc b/absl/strings/internal/pow10_helper.cc index c7f4875a..5c02ab8f 100644 --- a/absl/strings/internal/pow10_helper.cc +++ b/absl/strings/internal/pow10_helper.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,7 +17,7 @@ #include <cmath> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { namespace { @@ -118,5 +118,5 @@ double Pow10(int exp) { } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/pow10_helper.h b/absl/strings/internal/pow10_helper.h index 750051bd..c9a1b27f 100644 --- a/absl/strings/internal/pow10_helper.h +++ b/absl/strings/internal/pow10_helper.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,13 +17,13 @@ // 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_POW10_HELPER_H_ -#define ABSL_STRINGS_POW10_HELPER_H_ +#ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ +#define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ #include <vector> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { // Computes the precise value of 10^exp. (I.e. the nearest representable @@ -32,7 +32,7 @@ namespace strings_internal { double Pow10(int exp); } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl -#endif // ABSL_STRINGS_POW10_HELPER_H_ +#endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ diff --git a/absl/strings/internal/pow10_helper_test.cc b/absl/strings/internal/pow10_helper_test.cc index 371fe122..4a62a70d 100644 --- a/absl/strings/internal/pow10_helper_test.cc +++ b/absl/strings/internal/pow10_helper_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,7 +20,7 @@ #include "absl/strings/str_format.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { namespace { @@ -118,5 +118,5 @@ TEST(Pow10HelperTest, Works) { } // namespace } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/resize_uninitialized.h b/absl/strings/internal/resize_uninitialized.h index 2951bf84..ab1d8684 100644 --- a/absl/strings/internal/resize_uninitialized.h +++ b/absl/strings/internal/resize_uninitialized.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,54 +18,57 @@ #define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ #include <string> +#include <type_traits> #include <utility> #include "absl/base/port.h" #include "absl/meta/type_traits.h" // for void_t namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { // Is a subclass of true_type or false_type, depending on whether or not -// T has a resize_uninitialized member. -template <typename T, typename = void> -struct HasResizeUninitialized : std::false_type {}; -template <typename T> -struct HasResizeUninitialized< - T, absl::void_t<decltype(std::declval<T>().resize_uninitialized(237))>> - : std::true_type {}; +// T has a __resize_default_init member. +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 and by Google's internal +// ::string implementation. template <typename string_type> -void ResizeUninit(string_type* s, size_t new_size, std::true_type) { - s->resize_uninitialized(new_size); -} -template <typename string_type> -void ResizeUninit(string_type* s, size_t new_size, std::false_type) { - s->resize(new_size); -} +struct ResizeUninitializedTraits< + string_type, 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); + } +}; -// Returns true if the string implementation supports a resize where -// the new characters added to the string are left untouched. +// Returns true if the std::string implementation supports a resize where +// the new characters added to the std::string 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 HasResizeUninitialized<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 string with known data. Uses a Google extension to ::string. +// store of the std::string with known data. template <typename string_type, typename = void> inline void STLStringResizeUninitialized(string_type* s, size_t new_size) { - ResizeUninit(s, new_size, HasResizeUninitialized<string_type>()); + ResizeUninitializedTraits<string_type>::Resize(s, new_size); } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ diff --git a/absl/strings/internal/resize_uninitialized_test.cc b/absl/strings/internal/resize_uninitialized_test.cc index ad282efc..c5be0b12 100644 --- a/absl/strings/internal/resize_uninitialized_test.cc +++ b/absl/strings/internal/resize_uninitialized_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -24,44 +24,44 @@ struct resizable_string { void resize(size_t) { resize_call_count += 1; } }; -int resize_uninitialized_call_count = 0; +int resize_default_init_call_count = 0; -struct resize_uninitializable_string { +struct resize_default_init_string { void resize(size_t) { resize_call_count += 1; } - void resize_uninitialized(size_t) { resize_uninitialized_call_count += 1; } + void __resize_default_init(size_t) { resize_default_init_call_count += 1; } }; TEST(ResizeUninit, WithAndWithout) { resize_call_count = 0; - resize_uninitialized_call_count = 0; + resize_default_init_call_count = 0; { resizable_string rs; EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); EXPECT_FALSE( absl::strings_internal::STLStringSupportsNontrashingResize(&rs)); EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); absl::strings_internal::STLStringResizeUninitialized(&rs, 237); EXPECT_EQ(resize_call_count, 1); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); } resize_call_count = 0; - resize_uninitialized_call_count = 0; + resize_default_init_call_count = 0; { - resize_uninitializable_string rus; + resize_default_init_string rus; EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); EXPECT_TRUE( absl::strings_internal::STLStringSupportsNontrashingResize(&rus)); EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); absl::strings_internal::STLStringResizeUninitialized(&rus, 237); EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 1); + EXPECT_EQ(resize_default_init_call_count, 1); } } diff --git a/absl/strings/internal/stl_type_traits.h b/absl/strings/internal/stl_type_traits.h index fed7bf7c..af50be7c 100644 --- a/absl/strings/internal/stl_type_traits.h +++ b/absl/strings/internal/stl_type_traits.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -40,7 +40,7 @@ #include "absl/meta/type_traits.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { template <typename C, template <typename...> class T> @@ -243,6 +243,6 @@ struct IsStrictlyBaseOfAndConvertibleToSTLContainer IsConvertibleToSTLContainer<C>> {}; } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index e5e1eee5..667cc133 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -14,7 +14,7 @@ #include "absl/strings/internal/str_format/float_conversion.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { @@ -375,5 +375,5 @@ ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(); } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index 0af4c839..b6f708c6 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h @@ -7,6 +7,7 @@ #include <cstdio> #include <iomanip> #include <limits> +#include <memory> #include <sstream> #include <string> #include <type_traits> @@ -21,7 +22,7 @@ class Cord; class CordReader; namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { class FormatCountCapture; class FormatSink; @@ -36,12 +37,14 @@ struct HasUserDefinedConvert< T, void_t<decltype(AbslFormatConvert( std::declval<const T&>(), std::declval<ConversionSpec>(), std::declval<FormatSink*>()))>> : std::true_type {}; + 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`. + // Raw pointers. struct VoidPtr { VoidPtr() = default; @@ -55,7 +58,8 @@ ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv, FormatSinkImpl* sink); // Strings. -ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, ConversionSpec conv, +ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, + ConversionSpec conv, FormatSinkImpl* sink); ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv, FormatSinkImpl* sink); @@ -81,7 +85,7 @@ ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value, int precision = conv.precision(); if (precision >= 0) - to_write = std::min(to_write, static_cast<size_t>(precision)); + to_write = (std::min)(to_write, static_cast<size_t>(precision)); space_remaining = Excess(to_write, space_remaining); @@ -290,7 +294,7 @@ class FormatArgImpl { struct Manager<T, ByPointer> { static Data SetValue(const T& value) { Data data; - data.ptr = &value; + data.ptr = std::addressof(value); return data; } @@ -410,13 +414,13 @@ class FormatArgImpl { 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_(std::string, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__) ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern); } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ diff --git a/absl/strings/internal/str_format/arg_test.cc b/absl/strings/internal/str_format/arg_test.cc index 9cb9559c..c9c51951 100644 --- a/absl/strings/internal/str_format/arg_test.cc +++ b/absl/strings/internal/str_format/arg_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// https://www.apache.org/licenses/LICENSE-2.0 // #include "absl/strings/internal/str_format/arg.h" @@ -14,7 +14,7 @@ #include "absl/strings/str_format.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { @@ -109,5 +109,5 @@ const char kMyArray[] = "ABCDE"; } // namespace } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc index 5cf026b6..48a306d4 100644 --- a/absl/strings/internal/str_format/bind.cc +++ b/absl/strings/internal/str_format/bind.cc @@ -6,7 +6,7 @@ #include <string> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { @@ -26,12 +26,12 @@ class ArgContext { explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {} // Fill 'bound' with the results of applying the context's argument pack - // to the specified 'props'. We synthesize a BoundConversion by + // 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 *props, BoundConversion *bound); + bool Bind(const UnboundConversion* unbound, BoundConversion* bound); private: absl::Span<const FormatArgImpl> pack_; @@ -54,7 +54,8 @@ inline bool ArgContext::Bind(const UnboundConversion* unbound, // "A negative field width is taken as a '-' flag followed by a // positive field width." force_left = true; - width = -width; + // Make sure we don't overflow the width when negating it. + width = -std::max(width, -std::numeric_limits<int>::max()); } } @@ -160,7 +161,7 @@ bool BindWithPack(const UnboundConversion* props, } std::string Summarize(const UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args) { + absl::Span<const FormatArgImpl> args) { typedef SummarizingConverter Converter; std::string out; { @@ -188,7 +189,7 @@ std::ostream& Streamable::Print(std::ostream& os) const { } std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args) { + absl::Span<const FormatArgImpl> args) { size_t orig = out->size(); if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) { out->erase(orig); @@ -227,5 +228,5 @@ int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format, } } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h index df5562f6..db79eb6c 100644 --- a/absl/strings/internal/str_format/bind.h +++ b/absl/strings/internal/str_format/bind.h @@ -7,14 +7,13 @@ #include <string> #include "absl/base/port.h" -#include "absl/container/inlined_vector.h" #include "absl/strings/internal/str_format/arg.h" #include "absl/strings/internal/str_format/checker.h" #include "absl/strings/internal/str_format/parser.h" #include "absl/types/span.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { class UntypedFormatSpec; @@ -139,7 +138,17 @@ class Streamable { public: Streamable(const UntypedFormatSpecImpl& format, absl::Span<const FormatArgImpl> args) - : format_(format), args_(args.begin(), args.end()) {} + : format_(format) { + if (args.size() <= ABSL_ARRAYSIZE(few_args_)) { + for (size_t i = 0; i < args.size(); ++i) { + few_args_[i] = args[i]; + } + args_ = absl::MakeSpan(few_args_, args.size()); + } else { + many_args_.assign(args.begin(), args.end()); + args_ = many_args_; + } + } std::ostream& Print(std::ostream& os) const; @@ -149,12 +158,17 @@ class Streamable { private: const UntypedFormatSpecImpl& format_; - absl::InlinedVector<FormatArgImpl, 4> args_; + 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 std::string Summarize(UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args); + absl::Span<const FormatArgImpl> args); bool BindWithPack(const UnboundConversion* props, absl::Span<const FormatArgImpl> pack, BoundConversion* bound); @@ -163,10 +177,10 @@ bool FormatUntyped(FormatRawSinkImpl raw_sink, absl::Span<const FormatArgImpl> args); std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args); + absl::Span<const FormatArgImpl> args); inline std::string FormatPack(const UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args) { + absl::Span<const FormatArgImpl> args) { std::string out; AppendPack(&out, format, args); return out; @@ -177,7 +191,7 @@ int FprintF(std::FILE* output, UntypedFormatSpecImpl format, int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, absl::Span<const FormatArgImpl> args); -// Returned by Streamed(v). Converts via '%s' to the string created +// Returned by Streamed(v). Converts via '%s' to the std::string created // by std::ostream << v. template <typename T> class StreamedWrapper { @@ -193,7 +207,7 @@ class StreamedWrapper { }; } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc index 58d9e072..8bccc92a 100644 --- a/absl/strings/internal/str_format/bind_test.cc +++ b/absl/strings/internal/str_format/bind_test.cc @@ -1,24 +1,20 @@ #include "absl/strings/internal/str_format/bind.h" #include <string.h> +#include <limits> #include "gtest/gtest.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { -template <typename T, size_t N> -size_t ArraySize(T (&)[N]) { - return N; -} - class FormatBindTest : public ::testing::Test { public: bool Extract(const char *s, UnboundConversion *props, int *next) const { - absl::string_view src = s; - return ConsumeUnboundConversion(&src, props, next) && src.empty(); + return ConsumeUnboundConversion(s, s + strlen(s), props, next) == + s + strlen(s); } }; @@ -92,6 +88,20 @@ TEST_F(FormatBindTest, BindSingle) { } } +TEST_F(FormatBindTest, WidthUnderflowRegression) { + UnboundConversion props; + BoundConversion bound; + int next = 0; + const int args_i[] = {std::numeric_limits<int>::min(), 17}; + const FormatArgImpl args[] = {FormatArgImpl(args_i[0]), + FormatArgImpl(args_i[1])}; + ASSERT_TRUE(Extract("*d", &props, &next)); + ASSERT_TRUE(BindWithPack(&props, args, &bound)); + + EXPECT_EQ(bound.width(), std::numeric_limits<int>::max()); + EXPECT_EQ(bound.arg(), args + 1); +} + TEST_F(FormatBindTest, FormatPack) { struct Expectation { int line; @@ -129,5 +139,5 @@ TEST_F(FormatBindTest, FormatPack) { } // namespace } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/checker.h b/absl/strings/internal/str_format/checker.h index d0191968..262887cd 100644 --- a/absl/strings/internal/str_format/checker.h +++ b/absl/strings/internal/str_format/checker.h @@ -15,7 +15,7 @@ #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { constexpr bool AllOf() { return true; } @@ -321,7 +321,7 @@ constexpr bool ValidFormatImpl(string_view format) { #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc index b4f38979..2aa3b128 100644 --- a/absl/strings/internal/str_format/checker_test.cc +++ b/absl/strings/internal/str_format/checker_test.cc @@ -5,7 +5,7 @@ #include "absl/strings/str_format.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { @@ -63,32 +63,32 @@ TEST(StrFormatChecker, ValidFormat) { ValidFormat<int>("%% %d"), // ValidFormat<int>("%ld"), // ValidFormat<int>("%lld"), // - ValidFormat<std::string>("%s"), // - ValidFormat<std::string>("%10s"), // + ValidFormat<std::string>("%s"), // + ValidFormat<std::string>("%10s"), // ValidFormat<int>("%.10x"), // ValidFormat<int, int>("%*.3x"), // ValidFormat<int>("%1.d"), // ValidFormat<int>("%.d"), // ValidFormat<int, double>("%d %g"), // - ValidFormat<int, std::string>("%*s"), // + ValidFormat<int, std::string>("%*s"), // ValidFormat<int, double>("%.*f"), // ValidFormat<void (*)(), volatile int*>("%p %p"), // ValidFormat<string_view, const char*, double, void*>( "string_view=%s const char*=%s double=%f void*=%p)"), - ValidFormat<int>("%% %1$d"), // - ValidFormat<int>("%1$ld"), // - ValidFormat<int>("%1$lld"), // - ValidFormat<std::string>("%1$s"), // - ValidFormat<std::string>("%1$10s"), // - ValidFormat<int>("%1$.10x"), // - ValidFormat<int>("%1$*1$.*1$d"), // - ValidFormat<int, int>("%1$*2$.3x"), // - ValidFormat<int>("%1$1.d"), // - ValidFormat<int>("%1$.d"), // - ValidFormat<double, int>("%2$d %1$g"), // - ValidFormat<int, std::string>("%2$*1$s"), // - ValidFormat<int, double>("%2$.*1$f"), // + ValidFormat<int>("%% %1$d"), // + ValidFormat<int>("%1$ld"), // + ValidFormat<int>("%1$lld"), // + ValidFormat<std::string>("%1$s"), // + ValidFormat<std::string>("%1$10s"), // + ValidFormat<int>("%1$.10x"), // + ValidFormat<int>("%1$*1$.*1$d"), // + ValidFormat<int, int>("%1$*2$.3x"), // + ValidFormat<int>("%1$1.d"), // + ValidFormat<int>("%1$.d"), // + ValidFormat<double, int>("%2$d %1$g"), // + ValidFormat<int, std::string>("%2$*1$s"), // + ValidFormat<int, double>("%2$.*1$f"), // ValidFormat<void*, string_view, const char*, double>( "string_view=%2$s const char*=%3$s double=%4$f void*=%1$p " "repeat=%3$s)")}; @@ -100,25 +100,25 @@ TEST(StrFormatChecker, ValidFormat) { constexpr Case falses[] = { ValidFormat<int>(""), // - ValidFormat<e>("%s"), // - ValidFormat<e2>("%s"), // - ValidFormat<>("%s"), // - ValidFormat<>("%r"), // - ValidFormat<int>("%s"), // - ValidFormat<int>("%.1.d"), // - ValidFormat<int>("%*1d"), // - ValidFormat<int>("%1-d"), // + ValidFormat<e>("%s"), // + ValidFormat<e2>("%s"), // + ValidFormat<>("%s"), // + ValidFormat<>("%r"), // + ValidFormat<int>("%s"), // + ValidFormat<int>("%.1.d"), // + ValidFormat<int>("%*1d"), // + ValidFormat<int>("%1-d"), // ValidFormat<std::string, int>("%*s"), // - ValidFormat<int>("%*d"), // + ValidFormat<int>("%*d"), // ValidFormat<std::string>("%p"), // - ValidFormat<int (*)(int)>("%d"), // - - ValidFormat<>("%3$d"), // - ValidFormat<>("%1$r"), // - ValidFormat<int>("%1$s"), // - ValidFormat<int>("%1$.1.d"), // - ValidFormat<int>("%1$*2$1d"), // - ValidFormat<int>("%1$1-d"), // + ValidFormat<int (*)(int)>("%d"), // + + ValidFormat<>("%3$d"), // + ValidFormat<>("%1$r"), // + ValidFormat<int>("%1$s"), // + ValidFormat<int>("%1$.1.d"), // + ValidFormat<int>("%1$*2$1d"), // + ValidFormat<int>("%1$1-d"), // ValidFormat<std::string, int>("%2$*1$s"), // ValidFormat<std::string>("%1$p"), @@ -148,5 +148,5 @@ TEST(StrFormatChecker, LongFormat) { } // namespace } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index 95d57b67..751bfc34 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc @@ -1,6 +1,7 @@ #include <errno.h> #include <stdarg.h> #include <stdio.h> +#include <cctype> #include <cmath> #include <string> @@ -8,7 +9,7 @@ #include "absl/strings/internal/str_format/bind.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { @@ -33,7 +34,9 @@ std::string LengthModFor(long long) { return "ll"; } // NOLINT std::string LengthModFor(unsigned long long) { return "ll"; } // NOLINT std::string EscCharImpl(int v) { - if (isprint(v)) return std::string(1, static_cast<char>(v)); + if (std::isprint(static_cast<unsigned char>(v))) { + return std::string(1, static_cast<char>(v)); + } char buf[64]; int n = snprintf(buf, sizeof(buf), "\\%#.2x", static_cast<unsigned>(v & 0xff)); @@ -156,7 +159,7 @@ TEST_F(FormatConvertTest, StringPrecision) { } TEST_F(FormatConvertTest, Pointer) { -#if _MSC_VER +#ifdef _MSC_VER // MSVC's printf implementation prints pointers differently. We can't easily // compare our implementation to theirs. return; @@ -233,7 +236,7 @@ TEST_F(FormatConvertTest, Enum) { template <typename T> class TypedFormatConvertTest : public FormatConvertTest { }; -TYPED_TEST_CASE_P(TypedFormatConvertTest); +TYPED_TEST_SUITE_P(TypedFormatConvertTest); std::vector<std::string> AllFlagCombinations() { const char kFlags[] = {'-', '#', '0', '+', ' '}; @@ -364,6 +367,18 @@ typedef ::testing::Types< AllIntTypes; INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes, TypedFormatConvertTest, AllIntTypes); + +TEST_F(FormatConvertTest, VectorBool) { + // Make sure vector<bool>'s values behave as bools. + std::vector<bool> v = {true, false}; + const std::vector<bool> cv = {true, false}; + EXPECT_EQ("1,0,1,0", + FormatPack(UntypedFormatSpecImpl("%d,%d,%d,%d"), + absl::Span<const FormatArgImpl>( + {FormatArgImpl(v[0]), FormatArgImpl(v[1]), + FormatArgImpl(cv[0]), FormatArgImpl(cv[1])}))); +} + TEST_F(FormatConvertTest, Uint128) { absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979; absl::uint128 max = absl::Uint128Max(); @@ -390,7 +405,7 @@ TEST_F(FormatConvertTest, Uint128) { } TEST_F(FormatConvertTest, Float) { -#if _MSC_VER +#ifdef _MSC_VER // MSVC has a different rounding policy than us so we can't test our // implementation against the native one there. return; @@ -573,5 +588,5 @@ TEST_F(FormatConvertTest, ExpectedFailures) { } // namespace } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/extension.cc b/absl/strings/internal/str_format/extension.cc index e3b41c82..1a0c4172 100644 --- a/absl/strings/internal/str_format/extension.cc +++ b/absl/strings/internal/str_format/extension.cc @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,7 +20,7 @@ #include <string> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { // clang-format off @@ -82,5 +82,5 @@ bool FormatSinkImpl::PutPaddedString(string_view v, int w, int p, bool l) { } } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h index d401b4ed..4fbe4a06 100644 --- a/absl/strings/internal/str_format/extension.h +++ b/absl/strings/internal/str_format/extension.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -13,7 +13,6 @@ // 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_ @@ -29,7 +28,7 @@ class Cord; namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { @@ -361,7 +360,7 @@ enum class Conv : uint64_t { integral = d | i | u | o | x | X, floating = a | e | f | g | A | E | F | G, numeric = integral | floating, - string = s, // absl:ignore(std::string) + string = s, pointer = p }; @@ -408,7 +407,7 @@ inline size_t Excess(size_t used, size_t capacity) { } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc index 224fc923..4e23fefb 100644 --- a/absl/strings/internal/str_format/extension_test.cc +++ b/absl/strings/internal/str_format/extension_test.cc @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,6 +18,7 @@ #include <random> #include <string> + #include "absl/strings/str_format.h" #include "gtest/gtest.h" diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc index 7b617689..a0484feb 100644 --- a/absl/strings/internal/str_format/float_conversion.cc +++ b/absl/strings/internal/str_format/float_conversion.cc @@ -6,8 +6,10 @@ #include <cmath> #include <string> +#include "absl/base/config.h" + namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { @@ -335,7 +337,7 @@ bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out, static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp)) return true; -#if defined(__SIZEOF_INT128__) +#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>( @@ -481,5 +483,5 @@ bool ConvertFloatImpl(double v, const ConversionSpec &conv, } } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/float_conversion.h b/absl/strings/internal/str_format/float_conversion.h index 280c471a..5d76ce2b 100644 --- a/absl/strings/internal/str_format/float_conversion.h +++ b/absl/strings/internal/str_format/float_conversion.h @@ -4,7 +4,7 @@ #include "absl/strings/internal/str_format/extension.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { bool ConvertFloatImpl(float v, const ConversionSpec &conv, @@ -17,7 +17,7 @@ bool ConvertFloatImpl(long double v, const ConversionSpec &conv, FormatSinkImpl *sink); } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ diff --git a/absl/strings/internal/str_format/output.cc b/absl/strings/internal/str_format/output.cc index 010bf341..d5ead8d5 100644 --- a/absl/strings/internal/str_format/output.cc +++ b/absl/strings/internal/str_format/output.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,7 +18,7 @@ #include <cstring> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { @@ -68,5 +68,5 @@ void FILERawSink::Write(string_view v) { } } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/output.h b/absl/strings/internal/str_format/output.h index 0f3ab349..ba847471 100644 --- a/absl/strings/internal/str_format/output.h +++ b/absl/strings/internal/str_format/output.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -31,7 +31,7 @@ class Cord; namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { // RawSink implementation that writes into a char* buffer. @@ -97,7 +97,7 @@ auto InvokeFlush(T* out, string_view s) } } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ diff --git a/absl/strings/internal/str_format/output_test.cc b/absl/strings/internal/str_format/output_test.cc index 0a014cac..5c3c4afb 100644 --- a/absl/strings/internal/str_format/output_test.cc +++ b/absl/strings/internal/str_format/output_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,24 +17,17 @@ #include <sstream> #include <string> - #include "gmock/gmock.h" #include "gtest/gtest.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace { TEST(InvokeFlush, String) { std::string str = "ABC"; str_format_internal::InvokeFlush(&str, "DEF"); EXPECT_EQ(str, "ABCDEF"); - -#if UTIL_FORMAT_HAS_GLOBAL_STRING - std::string str2 = "ABC"; - str_format_internal::InvokeFlush(&str2, "DEF"); - EXPECT_EQ(str2, "ABCDEF"); -#endif // UTIL_FORMAT_HAS_GLOBAL_STRING } TEST(InvokeFlush, Stream) { @@ -75,6 +68,6 @@ TEST(BufferRawSink, Limits) { } } // namespace -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc index 119a711e..4b8ca4d2 100644 --- a/absl/strings/internal/str_format/parser.cc +++ b/absl/strings/internal/str_format/parser.cc @@ -14,8 +14,46 @@ #include <unordered_set> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { + +using CC = ConversionChar::Id; +using LM = LengthMod::Id; +ABSL_CONST_INIT const ConvTag kTags[256] = { + {}, {}, {}, {}, {}, {}, {}, {}, // 00-07 + {}, {}, {}, {}, {}, {}, {}, {}, // 08-0f + {}, {}, {}, {}, {}, {}, {}, {}, // 10-17 + {}, {}, {}, {}, {}, {}, {}, {}, // 18-1f + {}, {}, {}, {}, {}, {}, {}, {}, // 20-27 + {}, {}, {}, {}, {}, {}, {}, {}, // 28-2f + {}, {}, {}, {}, {}, {}, {}, {}, // 30-37 + {}, {}, {}, {}, {}, {}, {}, {}, // 38-3f + {}, CC::A, {}, CC::C, {}, CC::E, CC::F, CC::G, // @ABCDEFG + {}, {}, {}, {}, LM::L, {}, {}, {}, // HIJKLMNO + {}, {}, {}, CC::S, {}, {}, {}, {}, // PQRSTUVW + CC::X, {}, {}, {}, {}, {}, {}, {}, // XYZ[\]^_ + {}, CC::a, {}, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg + LM::h, CC::i, LM::j, {}, LM::l, {}, CC::n, CC::o, // hijklmno + CC::p, LM::q, {}, CC::s, LM::t, CC::u, {}, {}, // pqrstuvw + CC::x, {}, LM::z, {}, {}, {}, {}, {}, // xyz{|}! + {}, {}, {}, {}, {}, {}, {}, {}, // 80-87 + {}, {}, {}, {}, {}, {}, {}, {}, // 88-8f + {}, {}, {}, {}, {}, {}, {}, {}, // 90-97 + {}, {}, {}, {}, {}, {}, {}, {}, // 98-9f + {}, {}, {}, {}, {}, {}, {}, {}, // a0-a7 + {}, {}, {}, {}, {}, {}, {}, {}, // a8-af + {}, {}, {}, {}, {}, {}, {}, {}, // b0-b7 + {}, {}, {}, {}, {}, {}, {}, {}, // b8-bf + {}, {}, {}, {}, {}, {}, {}, {}, // c0-c7 + {}, {}, {}, {}, {}, {}, {}, {}, // c8-cf + {}, {}, {}, {}, {}, {}, {}, {}, // d0-d7 + {}, {}, {}, {}, {}, {}, {}, {}, // d8-df + {}, {}, {}, {}, {}, {}, {}, {}, // e0-e7 + {}, {}, {}, {}, {}, {}, {}, {}, // e8-ef + {}, {}, {}, {}, {}, {}, {}, {}, // f0-f7 + {}, {}, {}, {}, {}, {}, {}, {}, // f8-ff +}; + namespace { bool CheckFastPathSetting(const UnboundConversion& conv) { @@ -37,60 +75,17 @@ bool CheckFastPathSetting(const UnboundConversion& conv) { return should_be_basic == conv.flags.basic; } -// Keep a single table for all the conversion chars and length modifiers. -// We invert the length modifiers to make them negative so that we can easily -// test for them. -// Everything else is `none`, which is a negative constant. -using CC = ConversionChar::Id; -using LM = LengthMod::Id; -static constexpr std::int8_t none = -128; -static constexpr std::int8_t kIds[] = { - none, none, none, none, none, none, none, none, // 00-07 - none, none, none, none, none, none, none, none, // 08-0f - none, none, none, none, none, none, none, none, // 10-17 - none, none, none, none, none, none, none, none, // 18-1f - none, none, none, none, none, none, none, none, // 20-27 - none, none, none, none, none, none, none, none, // 28-2f - none, none, none, none, none, none, none, none, // 30-37 - none, none, none, none, none, none, none, none, // 38-3f - none, CC::A, none, CC::C, none, CC::E, CC::F, CC::G, // @ABCDEFG - none, none, none, none, ~LM::L, none, none, none, // HIJKLMNO - none, none, none, CC::S, none, none, none, none, // PQRSTUVW - CC::X, none, none, none, none, none, none, none, // XYZ[\]^_ - none, CC::a, none, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg - ~LM::h, CC::i, ~LM::j, none, ~LM::l, none, CC::n, CC::o, // hijklmno - CC::p, ~LM::q, none, CC::s, ~LM::t, CC::u, none, none, // pqrstuvw - CC::x, none, ~LM::z, none, none, none, none, none, // xyz{|}~! - none, none, none, none, none, none, none, none, // 80-87 - none, none, none, none, none, none, none, none, // 88-8f - none, none, none, none, none, none, none, none, // 90-97 - none, none, none, none, none, none, none, none, // 98-9f - none, none, none, none, none, none, none, none, // a0-a7 - none, none, none, none, none, none, none, none, // a8-af - none, none, none, none, none, none, none, none, // b0-b7 - none, none, none, none, none, none, none, none, // b8-bf - none, none, none, none, none, none, none, none, // c0-c7 - none, none, none, none, none, none, none, none, // c8-cf - none, none, none, none, none, none, none, none, // d0-d7 - none, none, none, none, none, none, none, none, // d8-df - none, none, none, none, none, none, none, none, // e0-e7 - none, none, none, none, none, none, none, none, // e8-ef - none, none, none, none, none, none, none, none, // f0-f7 - none, none, none, none, none, none, none, none, // f8-ff -}; - template <bool is_positional> -bool ConsumeConversion(string_view *src, UnboundConversion *conv, - int *next_arg) { - const char *pos = src->data(); - const char *const end = pos + src->size(); +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 false; \ - c = *pos++; \ +#define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR() \ + do { \ + if (ABSL_PREDICT_FALSE(pos == end)) return nullptr; \ + c = *pos++; \ } while (0) const auto parse_digits = [&] { @@ -100,10 +95,11 @@ bool ConsumeConversion(string_view *src, UnboundConversion *conv, // digit doesn't match the expected characters. int num_digits = std::numeric_limits<int>::digits10; for (;;) { - if (ABSL_PREDICT_FALSE(pos == end || !num_digits)) break; + 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; @@ -111,10 +107,10 @@ bool ConsumeConversion(string_view *src, UnboundConversion *conv, if (is_positional) { ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false; + 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 false; + if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; } ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); @@ -129,10 +125,9 @@ bool ConsumeConversion(string_view *src, UnboundConversion *conv, conv->flags.basic = false; for (; c <= '0';) { - // FIXME: We might be able to speed this up reusing the kIds lookup table - // from above. - // It might require changing Flags to be a plain integer where we can |= a - // value. + // FIXME: We might be able to speed this up reusing the lookup table from + // above. It might require changing Flags to be a plain integer where we + // can |= a value. switch (c) { case '-': conv->flags.left = true; @@ -160,20 +155,20 @@ flags_done: if (c >= '0') { int maybe_width = parse_digits(); if (!is_positional && c == '$') { - if (ABSL_PREDICT_FALSE(*next_arg != 0)) return false; + if (ABSL_PREDICT_FALSE(*next_arg != 0)) return nullptr; // Positional conversion. *next_arg = -1; conv->flags = Flags(); conv->flags.basic = true; - return ConsumeConversion<true>(src, conv, next_arg); + return ConsumeConversion<true>(original_pos, end, conv, next_arg); } conv->width.set_value(maybe_width); } else if (c == '*') { ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); if (is_positional) { - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false; + if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; conv->width.set_from_arg(parse_digits()); - if (ABSL_PREDICT_FALSE(c != '$')) return false; + if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); } else { conv->width.set_from_arg(++*next_arg); @@ -188,9 +183,9 @@ flags_done: } else if (c == '*') { ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); if (is_positional) { - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false; + if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; conv->precision.set_from_arg(parse_digits()); - if (c != '$') return false; + if (c != '$') return nullptr; ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); } else { conv->precision.set_from_arg(++*next_arg); @@ -201,14 +196,14 @@ flags_done: } } - std::int8_t id = kIds[static_cast<unsigned char>(c)]; + auto tag = GetTagForChar(c); - if (id < 0) { - if (ABSL_PREDICT_FALSE(id == none)) return false; + 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 = LengthMod::FromId(static_cast<LM>(~id)); + LengthMod length_mod = tag.as_length(); ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); if (c == 'h' && length_mod.id() == LengthMod::h) { conv->length_mod = LengthMod::FromId(LengthMod::hh); @@ -219,25 +214,24 @@ flags_done: } else { conv->length_mod = length_mod; } - id = kIds[static_cast<unsigned char>(c)]; - if (ABSL_PREDICT_FALSE(id < 0)) return false; + tag = GetTagForChar(c); + if (ABSL_PREDICT_FALSE(!tag.is_conv())) return nullptr; } assert(CheckFastPathSetting(*conv)); (void)(&CheckFastPathSetting); - conv->conv = ConversionChar::FromId(static_cast<CC>(id)); + conv->conv = tag.as_conv(); if (!is_positional) conv->arg_position = ++*next_arg; - *src = string_view(pos, end - pos); - return true; + return pos; } } // namespace -bool ConsumeUnboundConversion(string_view *src, UnboundConversion *conv, - int *next_arg) { - if (*next_arg < 0) return ConsumeConversion<true>(src, conv, next_arg); - return ConsumeConversion<false>(src, conv, next_arg); +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 { @@ -307,5 +301,5 @@ bool ParsedFormatBase::MatchesConversions( } } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h index 9842c117..d3357fde 100644 --- a/absl/strings/internal/str_format/parser.h +++ b/absl/strings/internal/str_format/parser.h @@ -16,7 +16,7 @@ #include "absl/strings/internal/str_format/extension.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { // The analyzed properties of a single specified conversion. @@ -64,17 +64,45 @@ struct UnboundConversion { ConversionChar conv; }; -// Consume conversion spec prefix (not including '%') of '*src' if valid. +// 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, the front of src is advanced such that src becomes the -// part following the conversion spec, and the spec part is broken down and -// returned in 'conv'. -// If invalid, returns false and leaves 'src' unmodified. -// For example: -// Given "d9", returns "d", and leaves src="9", -// Given "!", returns "" and leaves src="!". -bool ConsumeUnboundConversion(string_view* src, UnboundConversion* conv, - int* next_arg); +// 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` checking and conversions. +class ConvTag { + public: + constexpr ConvTag(ConversionChar::Id id) : tag_(id) {} // NOLINT + // We invert the length modifiers to make them negative so that we can easily + // test for them. + constexpr ConvTag(LengthMod::Id id) : tag_(~id) {} // NOLINT + // Everything else is -128, which is negative to make is_conv() simpler. + constexpr ConvTag() : tag_(-128) {} + + bool is_conv() const { return tag_ >= 0; } + bool is_length() const { return tag_ < 0 && tag_ != -128; } + ConversionChar as_conv() const { + assert(is_conv()); + return ConversionChar::FromId(static_cast<ConversionChar::Id>(tag_)); + } + LengthMod as_length() const { + assert(is_length()); + return LengthMod::FromId(static_cast<LengthMod::Id>(~tag_)); + } + + private: + std::int8_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'. @@ -89,51 +117,53 @@ bool ConsumeUnboundConversion(string_view* src, UnboundConversion* conv, template <typename Consumer> bool ParseFormatString(string_view src, Consumer consumer) { int next_arg = 0; - while (!src.empty()) { - const char* percent = - static_cast<const char*>(memchr(src.data(), '%', src.size())); + 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(src); + return consumer.Append(string_view(p, end - p)); } // We found a percent, so push the text run then process the percent. - size_t percent_loc = percent - src.data(); - if (!consumer.Append(string_view(src.data(), percent_loc))) return false; - if (percent + 1 >= src.data() + src.size()) return false; - - UnboundConversion conv; - - switch (percent[1]) { - case '%': - if (!consumer.Append("%")) return false; - src.remove_prefix(percent_loc + 2); - continue; - -#define PARSER_CASE(ch) \ - case #ch[0]: \ - src.remove_prefix(percent_loc + 2); \ - conv.conv = ConversionChar::FromId(ConversionChar::ch); \ - conv.arg_position = ++next_arg; \ - break; - ABSL_CONVERSION_CHARS_EXPAND_(PARSER_CASE, ); -#undef PARSER_CASE - - default: - src.remove_prefix(percent_loc + 1); - if (!ConsumeUnboundConversion(&src, &conv, &next_arg)) return false; - break; - } - if (next_arg == 0) { - // This indicates an error in the format std::string. - // The only way to get next_arg == 0 is to have a positional argument - // first which sets next_arg to -1 and then a non-positional argument - // which does ++next_arg. - // Checking here seems to be the cheapeast place to do it. + if (ABSL_PREDICT_FALSE(!consumer.Append(string_view(p, percent - p)))) { return false; } - if (!consumer.ConvertOne( - conv, string_view(percent + 1, src.data() - (percent + 1)))) { - 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 std::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; @@ -288,7 +318,7 @@ class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase { : ParsedFormatBase(s, allow_ignored, {C...}) {} }; } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc index 14d90344..d77a8ea5 100644 --- a/absl/strings/internal/str_format/parser_test.cc +++ b/absl/strings/internal/str_format/parser_test.cc @@ -1,15 +1,19 @@ #include "absl/strings/internal/str_format/parser.h" #include <string.h> + +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/macros.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace str_format_internal { namespace { +using testing::Pair; + TEST(LengthModTest, Names) { struct Expectation { int line; @@ -64,20 +68,21 @@ TEST(ConversionCharTest, Names) { class ConsumeUnboundConversionTest : public ::testing::Test { public: - typedef UnboundConversion Props; - string_view Consume(string_view* src) { + std::pair<string_view, string_view> Consume(string_view src) { int next = 0; - const char* prev_begin = src->data(); o = UnboundConversion(); // refresh - ConsumeUnboundConversion(src, &o, &next); - return {prev_begin, static_cast<size_t>(src->data() - prev_begin)}; + const char* p = ConsumeUnboundConversion( + src.data(), src.data() + src.size(), &o, &next); + if (!p) return {{}, src}; + return {string_view(src.data(), p - src.data()), + string_view(p, src.data() + src.size() - p)}; } bool Run(const char *fmt, bool force_positional = false) { - string_view src = fmt; int next = force_positional ? -1 : 0; o = UnboundConversion(); // refresh - return ConsumeUnboundConversion(&src, &o, &next) && src.empty(); + return ConsumeUnboundConversion(fmt, fmt + strlen(fmt), &o, &next) == + fmt + strlen(fmt); } UnboundConversion o; }; @@ -105,11 +110,7 @@ TEST_F(ConsumeUnboundConversionTest, ConsumeSpecification) { }; for (const auto& e : kExpect) { SCOPED_TRACE(e.line); - string_view src = e.src; - EXPECT_EQ(e.src, src); - string_view out = Consume(&src); - EXPECT_EQ(e.out, out); - EXPECT_EQ(e.src_post, src); + EXPECT_THAT(Consume(e.src), Pair(e.out, e.src_post)); } } @@ -247,6 +248,8 @@ TEST_F(ConsumeUnboundConversionTest, WidthAndPrecision) { EXPECT_FALSE(Run("1000000000.999999999d")); EXPECT_FALSE(Run("999999999.1000000000d")); + EXPECT_FALSE(Run("9999999999d")); + EXPECT_FALSE(Run(".9999999999d")); } TEST_F(ConsumeUnboundConversionTest, Flags) { @@ -387,5 +390,5 @@ TEST_F(ParsedFormatTest, ParsingFlagOrder) { } // namespace } // namespace str_format_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h index 90b06d6f..02787dd1 100644 --- a/absl/strings/internal/str_join_internal.h +++ b/absl/strings/internal/str_join_internal.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -43,7 +43,7 @@ #include "absl/strings/str_cat.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { // @@ -194,7 +194,7 @@ struct DefaultFormatter<std::unique_ptr<ValueType>> // and formats each element using the provided Formatter object. template <typename Iterator, typename Formatter> std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, - Formatter&& f) { + Formatter&& f) { std::string result; absl::string_view sep(""); for (Iterator it = start; it != end; ++it) { @@ -213,7 +213,7 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, // 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., string, absl::string_view), and an +// range of string-like objects (e.g., std::string, absl::string_view), and an // explicit Formatter argument was NOT specified. // // The optimization is that the needed space will be reserved in the output @@ -225,7 +225,7 @@ template <typename Iterator, typename std::iterator_traits<Iterator>::iterator_category, std::forward_iterator_tag>::value>::type> std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, - NoFormatter) { + NoFormatter) { std::string result; if (start != end) { // Sums size @@ -277,14 +277,15 @@ struct JoinTupleLoop<N, N> { template <typename... T, typename Formatter> std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep, - Formatter&& fmt) { + Formatter&& fmt) { std::string result; JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt); return result; } template <typename Iterator> -std::string JoinRange(Iterator first, Iterator last, absl::string_view separator) { +std::string JoinRange(Iterator first, Iterator last, + 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; @@ -293,7 +294,7 @@ std::string JoinRange(Iterator first, Iterator last, absl::string_view separator template <typename Range, typename Formatter> std::string JoinRange(const Range& range, absl::string_view separator, - Formatter&& fmt) { + Formatter&& fmt) { using std::begin; using std::end; return JoinAlgorithm(begin(range), end(range), separator, fmt); @@ -307,7 +308,7 @@ std::string JoinRange(const Range& range, absl::string_view separator) { } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h index 2300193a..92a678e0 100644 --- a/absl/strings/internal/str_split_internal.h +++ b/absl/strings/internal/str_split_internal.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -47,7 +47,7 @@ #endif // _GLIBCXX_DEBUG namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { // This class is implicitly constructible from everything that absl::string_view @@ -97,8 +97,8 @@ ConvertibleToStringView(std::string&& s) // NOLINT(runtime/explicit) } } - // Holds the data moved from temporary std::string arguments. Declared first so - // that 'value' can refer to 'copy_'. + // Holds the data moved from temporary std::string arguments. Declared first + // so that 'value' can refer to 'copy_'. std::string copy_; absl::string_view value_; }; @@ -377,10 +377,10 @@ class Splitter { // Partial specialization for a std::vector<std::string>. // - // Optimized for the common case of splitting to a std::vector<std::string>. In - // this case we first split the results to a std::vector<absl::string_view> so - // the returned std::vector<std::string> can have space reserved to avoid std::string - // moves. + // Optimized for the common case of splitting to a std::vector<std::string>. + // In this case we first split the results to a std::vector<absl::string_view> + // so the returned std::vector<std::string> can have space reserved to avoid + // std::string moves. template <typename A> struct ConvertToContainer<std::vector<std::string, A>, std::string, false> { std::vector<std::string, A> operator()(const Splitter& splitter) const { @@ -449,7 +449,7 @@ class Splitter { }; } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ diff --git a/absl/strings/internal/utf8.cc b/absl/strings/internal/utf8.cc index c6ab0d52..fe4a9beb 100644 --- a/absl/strings/internal/utf8.cc +++ b/absl/strings/internal/utf8.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,7 +17,7 @@ #include "absl/strings/internal/utf8.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) { @@ -49,5 +49,5 @@ size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) { } } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/internal/utf8.h b/absl/strings/internal/utf8.h index 59c4f5b4..b1bb954e 100644 --- a/absl/strings/internal/utf8.h +++ b/absl/strings/internal/utf8.h @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -13,7 +13,6 @@ // limitations under the License. // // UTF8 utilities, implemented to reduce dependencies. -// #ifndef ABSL_STRINGS_INTERNAL_UTF8_H_ #define ABSL_STRINGS_INTERNAL_UTF8_H_ @@ -22,7 +21,7 @@ #include <cstdint> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { // For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes @@ -43,7 +42,7 @@ enum { kMaxEncodedUTF8Size = 4 }; size_t EncodeUTF8Char(char *buffer, char32_t utf8_char); } // namespace strings_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_INTERNAL_UTF8_H_ diff --git a/absl/strings/internal/utf8_test.cc b/absl/strings/internal/utf8_test.cc index 64cec70d..88dd5036 100644 --- a/absl/strings/internal/utf8_test.cc +++ b/absl/strings/internal/utf8_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -22,12 +22,17 @@ namespace { +#if !defined(__cpp_char8_t) +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++2a-compat" +#endif TEST(EncodeUTF8Char, BasicFunction) { std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"}, - {0x00A3, u8"\u00A3"}, - {0x00010000, u8"\U00010000"}, - {0x0000FFFF, u8"\U0000FFFF"}, - {0x0010FFFD, u8"\U0010FFFD"}}; + {0x00A3, u8"\u00A3"}, + {0x00010000, u8"\U00010000"}, + {0x0000FFFF, u8"\U0000FFFF"}, + {0x0010FFFD, u8"\U0010FFFD"}}; for (auto &test : tests) { char buf0[7] = {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}; char buf1[7] = {'\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'}; @@ -53,5 +58,9 @@ TEST(EncodeUTF8Char, BasicFunction) { EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1), absl::strings_internal::kMaxEncodedUTF8Size); } +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#endif // !defined(__cpp_char8_t) } // namespace diff --git a/absl/strings/match.cc b/absl/strings/match.cc index 12ba8edf..01ed1f15 100644 --- a/absl/strings/match.cc +++ b/absl/strings/match.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,16 +17,7 @@ #include "absl/strings/internal/memutil.h" namespace absl { -inline namespace lts_2018_12_18 { - -namespace { -bool CaseEqual(absl::string_view piece1, absl::string_view piece2) { - return (piece1.size() == piece2.size() && - 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(), - piece1.size())); - // memcasecmp uses ascii_tolower(). -} -} // namespace +inline namespace lts_2019_08_08 { bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) { return (piece1.size() == piece2.size() && @@ -37,13 +28,13 @@ bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) { bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) { return (text.size() >= prefix.size()) && - CaseEqual(text.substr(0, prefix.size()), prefix); + EqualsIgnoreCase(text.substr(0, prefix.size()), prefix); } bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) { return (text.size() >= suffix.size()) && - CaseEqual(text.substr(text.size() - suffix.size()), suffix); + EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/match.h b/absl/strings/match.h index 5805207c..15fdc0c8 100644 --- a/absl/strings/match.h +++ b/absl/strings/match.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -38,7 +38,7 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // StrContains() // @@ -63,8 +63,7 @@ inline bool EndsWith(absl::string_view text, absl::string_view suffix) { return suffix.empty() || (text.size() >= suffix.size() && memcmp(text.data() + (text.size() - suffix.size()), suffix.data(), - suffix.size()) == 0 - ); + suffix.size()) == 0); } // EqualsIgnoreCase() @@ -75,17 +74,17 @@ bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2); // StartsWithIgnoreCase() // -// Returns whether a given ASCII string `text` starts with `starts_with`, +// Returns whether a given ASCII string `text` starts with `prefix`, // ignoring case in the comparison. bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix); // EndsWithIgnoreCase() // -// Returns whether a given ASCII string `text` ends with `ends_with`, ignoring +// Returns whether a given ASCII string `text` ends with `suffix`, ignoring // case in the comparison. bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix); -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_MATCH_H_ diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc index c21e00bf..4c313dda 100644 --- a/absl/strings/match_test.cc +++ b/absl/strings/match_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -19,7 +19,7 @@ namespace { TEST(MatchTest, StartsWith) { - const std::string s1("123" "\0" "456", 7); + const std::string s1("123\0abc", 7); const absl::string_view a("foobar"); const absl::string_view b(s1); const absl::string_view e; @@ -36,7 +36,7 @@ TEST(MatchTest, StartsWith) { } TEST(MatchTest, EndsWith) { - const std::string s1("123" "\0" "456", 7); + const std::string s1("123\0abc", 7); const absl::string_view a("foobar"); const absl::string_view b(s1); const absl::string_view e; diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index 4c3ddb34..2bac4adc 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -35,18 +35,19 @@ #include "absl/strings/ascii.h" #include "absl/strings/charconv.h" #include "absl/strings/internal/memutil.h" +#include "absl/strings/match.h" #include "absl/strings/str_cat.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { -bool SimpleAtof(absl::string_view str, float* value) { - *value = 0.0; +bool SimpleAtof(absl::string_view str, float* out) { + *out = 0.0; str = StripAsciiWhitespace(str); if (!str.empty() && str[0] == '+') { str.remove_prefix(1); } - auto result = absl::from_chars(str.data(), str.data() + str.size(), *value); + auto result = absl::from_chars(str.data(), str.data() + str.size(), *out); if (result.ec == std::errc::invalid_argument) { return false; } @@ -54,25 +55,25 @@ bool SimpleAtof(absl::string_view str, float* value) { // not all non-whitespace characters consumed return false; } - // from_chars() with DR 3801's current wording will return max() on + // 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 (*value > 1.0) { - *value = std::numeric_limits<float>::infinity(); - } else if (*value < -1.0) { - *value = -std::numeric_limits<float>::infinity(); + 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(absl::string_view str, double* value) { - *value = 0.0; +bool SimpleAtod(absl::string_view str, double* out) { + *out = 0.0; str = StripAsciiWhitespace(str); if (!str.empty() && str[0] == '+') { str.remove_prefix(1); } - auto result = absl::from_chars(str.data(), str.data() + str.size(), *value); + auto result = absl::from_chars(str.data(), str.data() + str.size(), *out); if (result.ec == std::errc::invalid_argument) { return false; } @@ -80,13 +81,13 @@ bool SimpleAtod(absl::string_view str, double* value) { // not all non-whitespace characters consumed return false; } - // from_chars() with DR 3801's current wording will return max() on + // 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 (*value > 1.0) { - *value = std::numeric_limits<double>::infinity(); - } else if (*value < -1.0) { - *value = -std::numeric_limits<double>::infinity(); + if (*out > 1.0) { + *out = std::numeric_limits<double>::infinity(); + } else if (*out < -1.0) { + *out = -std::numeric_limits<double>::infinity(); } } return true; @@ -94,14 +95,6 @@ bool SimpleAtod(absl::string_view str, double* value) { namespace { -// TODO(rogeeff): replace with the real released thing once we figure out what -// it is. -inline bool CaseEqual(absl::string_view piece1, absl::string_view piece2) { - return (piece1.size() == piece2.size() && - 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(), - piece1.size())); -} - // 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]; @@ -137,18 +130,18 @@ inline void PutTwoDigits(size_t i, char* buf) { } // namespace -bool SimpleAtob(absl::string_view str, bool* value) { - ABSL_RAW_CHECK(value != nullptr, "Output pointer must not be nullptr."); - if (CaseEqual(str, "true") || CaseEqual(str, "t") || - CaseEqual(str, "yes") || CaseEqual(str, "y") || - CaseEqual(str, "1")) { - *value = true; +bool SimpleAtob(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 (CaseEqual(str, "false") || CaseEqual(str, "f") || - CaseEqual(str, "no") || CaseEqual(str, "n") || - CaseEqual(str, "0")) { - *value = false; + if (EqualsIgnoreCase(str, "false") || EqualsIgnoreCase(str, "f") || + EqualsIgnoreCase(str, "no") || EqualsIgnoreCase(str, "n") || + EqualsIgnoreCase(str, "0")) { + *out = false; return true; } return false; @@ -910,5 +903,5 @@ bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) { } } // namespace numbers_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index 250d2603..e9878016 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -38,48 +38,53 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // SimpleAtoi() // // Converts the given string into an integer value, returning `true` if // successful. The string must reflect a base-10 integer (optionally followed or // preceded by ASCII whitespace) whose value falls within the range of the -// integer type. +// integer type. If any errors are encountered, this function returns `false`, +// leaving `out` in an unspecified state. template <typename int_type> -ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out); +ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out); // SimpleAtof() // // Converts the given string (optionally followed or preceded by ASCII // whitespace) into a float, which may be rounded on overflow or underflow. -// See http://en.cppreference.com/w/c/string/byte/strtof for details about the -// allowed formats for `str`. -ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* value); +// See https://en.cppreference.com/w/c/string/byte/strtof for details about the +// allowed formats for `str`. If any errors are encountered, this function +// returns `false`, leaving `out` in an unspecified state. +ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out); // SimpleAtod() // // Converts the given string (optionally followed or preceded by ASCII // whitespace) into a double, which may be rounded on overflow or underflow. -// See http://en.cppreference.com/w/c/string/byte/strtof for details about the -// allowed formats for `str`. -ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* value); +// See https://en.cppreference.com/w/c/string/byte/strtof for details about the +// allowed formats for `str`. If any errors are encountered, this function +// returns `false`, leaving `out` in an unspecified state. +ABSL_MUST_USE_RESULT bool SimpleAtod(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". -ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* value); +// 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(absl::string_view str, bool* out); -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl // End of public API. Implementation details follow. namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace numbers_internal { // safe_strto?() functions for implementing SimpleAtoi() @@ -178,11 +183,11 @@ ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out, // preceded by ASCII whitespace, with a value in the range of the corresponding // integer type. template <typename int_type> -ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out) { - return numbers_internal::safe_strtoi_base(s, out, 10); +ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) { + return numbers_internal::safe_strtoi_base(str, out, 10); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_NUMBERS_H_ diff --git a/absl/strings/numbers_benchmark.cc b/absl/strings/numbers_benchmark.cc index 0570b758..54dbedd3 100644 --- a/absl/strings/numbers_benchmark.cc +++ b/absl/strings/numbers_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc index 099326c2..77d7e783 100644 --- a/absl/strings/numbers_test.cc +++ b/absl/strings/numbers_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -191,7 +191,8 @@ void CheckUInt64(uint64_t x) { EXPECT_EQ(expected, std::string(&buffer[1], actual)) << " Input " << x; char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]); - EXPECT_EQ(expected, std::string(&buffer[1], generic_actual)) << " Input " << x; + EXPECT_EQ(expected, std::string(&buffer[1], generic_actual)) + << " Input " << x; char* my_actual = absl::numbers_internal::FastIntToBuffer(MyUInt64(x), &buffer[1]); @@ -712,7 +713,7 @@ TEST(stringtest, safe_strtou64_base_length_delimited) { } } -// feenableexcept() and fedisableexcept() are missing on Mac OS X, MSVC, +// feenableexcept() and fedisableexcept() are missing on macOS, MSVC, // and WebAssembly. #if defined(_MSC_VER) || defined(__APPLE__) || defined(__EMSCRIPTEN__) #define ABSL_MISSING_FEENABLEEXCEPT 1 @@ -784,7 +785,7 @@ void ExhaustiveFloat(uint32_t cases, R&& runnable) { if (iters_per_float == 0) iters_per_float = 1; for (float f : floats) { if (f == last) continue; - float testf = nextafter(last, std::numeric_limits<float>::max()); + float testf = std::nextafter(last, std::numeric_limits<float>::max()); runnable(testf); runnable(-testf); last = testf; @@ -798,7 +799,7 @@ void ExhaustiveFloat(uint32_t cases, R&& runnable) { last = testf; } } - testf = nextafter(f, 0.0f); + testf = std::nextafter(f, 0.0f); if (testf > last) { runnable(testf); runnable(-testf); @@ -879,8 +880,8 @@ TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) { char buf[kSixDigitsToBufferSize]; ABSL_RAW_LOG( INFO, "%s", - absl::StrCat("Exp ", exponent, " powten=", powten, "(", - powten, ") (", + absl::StrCat("Exp ", exponent, " powten=", powten, "(", powten, + ") (", std::string(buf, SixDigitsToBuffer(powten, buf)), ")") .c_str()); } diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 2f2e5315..73b9e0ba 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -23,7 +23,7 @@ #include "absl/strings/internal/resize_uninitialized.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { AlphaNum::AlphaNum(Hex hex) { char* const end = &digits_[numbers_internal::kFastToBufferSize]; @@ -79,7 +79,7 @@ AlphaNum::AlphaNum(Dec dec) { // ---------------------------------------------------------------------- // StrCat() -// This merges the given strings or integers, with no delimiter. This +// 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. // ---------------------------------------------------------------------- @@ -90,7 +90,9 @@ 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(); - memcpy(out, x.data(), x.size()); + if (x.size() != 0) { + memcpy(out, x.data(), x.size()); + } return after; } @@ -120,7 +122,7 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) { } std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, - const AlphaNum& d) { + const AlphaNum& d) { std::string result; strings_internal::STLStringResizeUninitialized( &result, a.size() + b.size() + c.size() + d.size()); @@ -147,8 +149,10 @@ std::string CatPieces(std::initializer_list<absl::string_view> pieces) { char* out = begin; for (const absl::string_view piece : pieces) { const size_t this_size = piece.size(); - memcpy(out, piece.data(), this_size); - out += this_size; + if (this_size != 0) { + memcpy(out, piece.data(), this_size); + out += this_size; + } } assert(out == begin + result.size()); return result; @@ -177,8 +181,10 @@ void AppendPieces(std::string* dest, char* out = begin + old_size; for (const absl::string_view piece : pieces) { const size_t this_size = piece.size(); - memcpy(out, piece.data(), this_size); - out += this_size; + if (this_size != 0) { + memcpy(out, piece.data(), this_size); + out += this_size; + } } assert(out == begin + dest->size()); } @@ -237,5 +243,5 @@ void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, assert(out == begin + dest->size()); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index edda40ad..c2700475 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -37,12 +37,12 @@ // attempt to pass ':' instead of ":" might result in a 58 ending up in your // result. // -// Bools convert to "0" or "1". +// 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 @@ -57,13 +57,14 @@ #include <cstdint> #include <string> #include <type_traits> +#include <vector> #include "absl/base/port.h" #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { // AlphaNumBuffer allows a way to pass a string to StrCat without having to do @@ -79,8 +80,8 @@ struct AlphaNumBuffer { // 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". +// 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, @@ -246,6 +247,7 @@ class AlphaNum { AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit) AlphaNum(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) @@ -269,6 +271,17 @@ class AlphaNum { 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: absl::string_view piece_; char digits_[numbers_internal::kFastToBufferSize]; @@ -318,16 +331,15 @@ ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) { ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b); ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c); + const AlphaNum& c); ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d); + const AlphaNum& c, const AlphaNum& d); // Support 5 or more arguments template <typename... AV> -ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d, - const AlphaNum& e, - const AV&... args) { +ABSL_MUST_USE_RESULT inline std::string 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()...}); @@ -345,18 +357,18 @@ ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, const AlphaNum // 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: // -// string s = "foo"; +// std::string s = "foo"; // s += s; // // This output is undefined: // -// string s = "foo"; +// std::string s = "foo"; // StrAppend(&s, s); // // This output is undefined as well, since `absl::string_view` does not own its // data: // -// string s = "foobar"; +// std::string s = "foobar"; // absl::string_view p = s; // StrAppend(&s, p); @@ -389,7 +401,7 @@ SixDigits(double d) { return result; } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_STR_CAT_H_ diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc index b6df9e30..14c63b3f 100644 --- a/absl/strings/str_cat_benchmark.cc +++ b/absl/strings/str_cat_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc index 07141072..29db9c02 100644 --- a/absl/strings/str_cat_test.cc +++ b/absl/strings/str_cat_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,6 +18,7 @@ #include <cstdint> #include <string> +#include <vector> #include "gtest/gtest.h" #include "absl/strings/substitute.h" @@ -106,11 +107,7 @@ TEST(StrCat, Enums) { TEST(StrCat, Basics) { std::string result; - std::string strs[] = { - "Hello", - "Cruel", - "World" - }; + std::string strs[] = {"Hello", "Cruel", "World"}; std::string stdstrs[] = { "std::Hello", @@ -164,9 +161,10 @@ TEST(StrCat, Basics) { result = absl::StrCat(ui64s[0], ", ", ui64s[1], "!"); EXPECT_EQ(result, "12345678910, 10987654321!"); - std::string one = "1"; // Actually, it's the size of this std::string that we want; a - // 64-bit build distinguishes between size_t and uint64_t, - // even though they're both unsigned 64-bit values. + std::string one = + "1"; // Actually, it's the size of this std::string that we want; a + // 64-bit build distinguishes between size_t and uint64_t, + // even though they're both unsigned 64-bit values. result = absl::StrCat("And a ", one.size(), " and a ", &result[2] - &result[0], " and a ", one, " 2 3 4", "!"); EXPECT_EQ(result, "And a 1 and a 2 and a 1 2 3 4!"); @@ -306,11 +304,7 @@ TEST(StrCat, MaxArgs) { TEST(StrAppend, Basics) { std::string result = "existing text"; - std::string strs[] = { - "Hello", - "Cruel", - "World" - }; + std::string strs[] = {"Hello", "Cruel", "World"}; std::string stdstrs[] = { "std::Hello", @@ -365,9 +359,10 @@ TEST(StrAppend, Basics) { absl::StrAppend(&result, ui64s[0], ", ", ui64s[1], "!"); EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!"); - std::string one = "1"; // Actually, it's the size of this std::string that we want; a - // 64-bit build distinguishes between size_t and uint64_t, - // even though they're both unsigned 64-bit values. + std::string one = + "1"; // Actually, it's the size of this std::string that we want; a + // 64-bit build distinguishes between size_t and uint64_t, + // even though they're both unsigned 64-bit values. old_size = result.size(); absl::StrAppend(&result, "And a ", one.size(), " and a ", &result[2] - &result[0], " and a ", one, " 2 3 4", "!"); @@ -401,6 +396,32 @@ TEST(StrAppend, Basics) { "No limit thanks to C++11's variadic templates"); } +TEST(StrCat, VectorBoolReferenceTypes) { + std::vector<bool> v; + v.push_back(true); + v.push_back(false); + std::vector<bool> const& cv = v; + // Test that vector<bool>::reference and vector<bool>::const_reference + // are handled as if the were really bool types and not the proxy types + // they really are. + std::string result = absl::StrCat(v[0], v[1], cv[0], cv[1]); // NOLINT + EXPECT_EQ(result, "1010"); +} + +// Passing nullptr to memcpy is undefined behavior and this test +// provides coverage of codepaths that handle empty strings with nullptrs. +TEST(StrCat, AvoidsMemcpyWithNullptr) { + EXPECT_EQ(absl::StrCat(42, absl::string_view{}), "42"); + + // Cover CatPieces code. + EXPECT_EQ(absl::StrCat(1, 2, 3, 4, 5, absl::string_view{}), "12345"); + + // Cover AppendPieces. + std::string result; + absl::StrAppend(&result, 1, 2, 3, 4, 5, absl::string_view{}); + EXPECT_EQ(result, "12345"); +} + #ifdef GTEST_HAS_DEATH_TEST TEST(StrAppend, Death) { std::string s = "self"; diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index 7b19d411..b4d1b7bd 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,11 +20,13 @@ // 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, the `str_format` uses a "format string" to -// perform argument substitutions based on types. +// perform argument substitutions based on types. See the `FormatSpec` section +// below for format string documentation. // // Example: // -// string s = absl::StrFormat("%s %s You have $%d!", "Hello", name, dollars); +// std::string s = absl::StrFormat( +// "%s %s You have $%d!", "Hello", name, dollars); // // The library consists of the following basic utilities: // @@ -49,7 +51,7 @@ // * 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.) +// 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: @@ -66,6 +68,7 @@ // In addition, the `str_format` library provides extension points for // augmenting formatting to new types. These extensions are fully documented // within the `str_format_extension.h` header file. + #ifndef ABSL_STRINGS_STR_FORMAT_H_ #define ABSL_STRINGS_STR_FORMAT_H_ @@ -79,7 +82,7 @@ #include "absl/strings/internal/str_format/parser.h" // IWYU pragma: export namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // UntypedFormatSpec // @@ -90,7 +93,7 @@ inline namespace lts_2018_12_18 { // Example: // // absl::UntypedFormatSpec format("%d"); -// string out; +// std::string out; // CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)})); class UntypedFormatSpec { public: @@ -136,8 +139,8 @@ str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) { // Example: // // int n = 0; -// string s = absl::StrFormat("%s%d%n", "hello", 123, -// absl::FormatCountCapture(&n)); +// std::string s = absl::StrFormat("%s%d%n", "hello", 123, +// absl::FormatCountCapture(&n)); // EXPECT_EQ(8, n); class FormatCountCapture { public: @@ -157,10 +160,15 @@ class FormatCountCapture { // FormatSpec // // The `FormatSpec` type defines the makeup of a format string within the -// `str_format` library. You should not need to use or manipulate this type -// directly. A `FormatSpec` is a variadic class template that is evaluated at -// compile-time, according to the format string and arguments that are passed -// to it. +// `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: @@ -187,7 +195,7 @@ class FormatCountCapture { // A format string generally follows the POSIX syntax as used within the POSIX // `printf` specification. // -// (See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html.) +// (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html.) // // In specific, the `FormatSpec` supports the following type specifiers: // * `c` for characters @@ -206,6 +214,11 @@ class FormatCountCapture { // written to this point. The resulting value must be captured within an // `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. // @@ -221,10 +234,10 @@ class FormatCountCapture { // "%e", .01 -> "1.00000e-2" // "%a", -3.0 -> "-0x1.8p+1" // "%g", .01 -> "1e-2" -// "%p", *int -> "0x7ffdeb6ad2a4" +// "%p", (void*)&value -> "0x7ffdeb6ad2a4" // // int n = 0; -// string s = absl::StrFormat( +// std::string s = absl::StrFormat( // "%s%d%n", "hello", 123, absl::FormatCountCapture(&n)); // EXPECT_EQ(8, n); // @@ -291,14 +304,14 @@ using ParsedFormat = str_format_internal::ExtendedParsedFormat< // // Example: // -// string s = absl::StrFormat( +// std::string s = 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> ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format, - const Args&... args) { + const Args&... args) { return str_format_internal::FormatPack( str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); @@ -312,11 +325,12 @@ ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format, // // Example: // -// string orig("For example PI is approximately "); +// std::string orig("For example PI is approximately "); // std::cout << StrAppendFormat(&orig, "%12.6f", 3.14); template <typename... Args> -std::string& StrAppendFormat(std::string* dst, const FormatSpec<Args...>& format, - const Args&... args) { +std::string& StrAppendFormat(std::string* 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)...}); @@ -435,7 +449,8 @@ class FormatRawSink { // `absl::FormatRawSink` interface), using a format string and zero or more // additional arguments. // -// By default, `string` and `std::ostream` are supported as destination objects. +// By default, `std::string` and `std::ostream` are supported as destination +// objects. If a `std::string` is used the formatted string is appended to it. // // `absl::Format()` is a generic version of `absl::StrFormat(), for custom // sinks. The format string, like format strings for `StrFormat()`, is checked @@ -484,9 +499,10 @@ using FormatArg = str_format_internal::FormatArgImpl; // // Example: // -// std::optional<string> FormatDynamic(const string& in_format, -// const vector<string>& in_args) { -// string out; +// std::optional<std::string> FormatDynamic( +// const std::string& in_format, +// const vector<std::string>& in_args) { +// std::string out; // std::vector<absl::FormatArg> args; // for (const auto& v : in_args) { // // It is important that 'v' is a reference to the objects in in_args. @@ -509,6 +525,7 @@ ABSL_MUST_USE_RESULT inline bool FormatUntyped( str_format_internal::UntypedFormatSpecImpl::Extract(format), args); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl + #endif // ABSL_STRINGS_STR_FORMAT_H_ diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index 77b8647f..bb0f58bf 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc @@ -10,11 +10,11 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace { using str_format_internal::FormatArgImpl; -class FormatEntryPointTest : public ::testing::Test { }; +using FormatEntryPointTest = ::testing::Test; TEST_F(FormatEntryPointTest, Format) { std::string sink; @@ -31,8 +31,8 @@ TEST_F(FormatEntryPointTest, UntypedFormat) { "", "a", "%80d", -#if !defined(_MSC_VER) && !defined(__ANDROID__) - // MSVC and Android don't support positional syntax. +#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__) + // MSVC, NaCL and Android don't support positional syntax. "complicated multipart %% %1$d format %1$0999d", #endif // _MSC_VER }; @@ -154,17 +154,20 @@ TEST_F(FormatEntryPointTest, Stream) { "", "a", "%80d", -#if !defined(_MSC_VER) && !defined(__ANDROID__) - // MSVC doesn't support positional syntax. + "%d %u %c %s %f %g", +#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__) + // MSVC, NaCL and Android don't support positional syntax. "complicated multipart %% %1$d format %1$080d", #endif // _MSC_VER }; std::string buf(4096, '\0'); for (const auto& fmt : formats) { - const auto parsed = ParsedFormat<'d'>::NewAllowIgnored(fmt); + const auto parsed = + ParsedFormat<'d', 'u', 'c', 's', 'f', 'g'>::NewAllowIgnored(fmt); std::ostringstream oss; - oss << StreamFormat(*parsed, 123); - int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), 123); + oss << StreamFormat(*parsed, 123, 3, 49, "multistreaming!!!", 1.01, 1.01); + int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), // + 123, 3, 49, "multistreaming!!!", 1.01, 1.01); ASSERT_TRUE(oss) << fmt; ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size()) << fmt_result; @@ -272,7 +275,7 @@ TEST_F(FormatEntryPointTest, FPrintFError) { EXPECT_EQ(errno, EBADF); } -#if __GLIBC__ +#ifdef __GLIBC__ TEST_F(FormatEntryPointTest, FprintfTooLarge) { std::FILE* f = std::fopen("/dev/null", "w"); int width = 2000000000; @@ -342,7 +345,7 @@ TEST(StrFormat, BehavesAsDocumented) { EXPECT_EQ(StrFormat("%c", int{'a'}), "a"); EXPECT_EQ(StrFormat("%c", long{'a'}), "a"); // NOLINT EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a"); - // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++" + // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++" // Formats std::string, char*, string_view, and Cord. EXPECT_EQ(StrFormat("%s", "C"), "C"); EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++"); @@ -459,7 +462,7 @@ std::string SummarizeParsedFormat(const ParsedFormatBase& pc) { return out; } -class ParsedFormatTest : public testing::Test {}; +using ParsedFormatTest = ::testing::Test; TEST_F(ParsedFormatTest, SimpleChecked) { EXPECT_EQ("[ABC]{d:1$d}[DEF]", @@ -601,28 +604,46 @@ TEST_F(ParsedFormatTest, RegressionMixPositional) { EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o"))); } +using FormatWrapperTest = ::testing::Test; + +// Plain wrapper for StrFormat. +template <typename... Args> +std::string WrappedFormat(const absl::FormatSpec<Args...>& format, + const Args&... args) { + return StrFormat(format, args...); +} + +TEST_F(FormatWrapperTest, ConstexprStringFormat) { + EXPECT_EQ(WrappedFormat("%s there", "hello"), "hello there"); +} + +TEST_F(FormatWrapperTest, ParsedFormat) { + ParsedFormat<'s'> format("%s there"); + EXPECT_EQ(WrappedFormat(format, "hello"), "hello there"); +} + } // namespace -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl // Some codegen thunks that we can use to easily dump the generated assembly for // different StrFormat calls. -std::string CodegenAbslStrFormatInt(int i) { // NOLINT +std::string CodegenAbslStrFormatInt(int i) { // NOLINT return absl::StrFormat("%d", i); } std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s, - int64_t i64) { // NOLINT + int64_t i64) { // NOLINT return absl::StrFormat("%d %s %d", i, s, i64); } -void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT +void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT absl::StrAppendFormat(out, "%d", i); } void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i, - const std::string& s, - int64_t i64) { // NOLINT + const std::string& s, + int64_t i64) { // NOLINT absl::StrAppendFormat(out, "%d %s %d", i, s, i64); } diff --git a/absl/strings/str_join.h b/absl/strings/str_join.h index dc476a22..c6c0c98a 100644 --- a/absl/strings/str_join.h +++ b/absl/strings/str_join.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,13 +18,13 @@ // ----------------------------------------------------------------------------- // // This header file contains functions for joining a range of elements and -// returning the result as a string. 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 elements -// to be joined, using the same formatting that `absl::StrCat()` uses. This -// package defines a number of default formatters, and you can define your own -// implementations. +// returning the result as a std::string. 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 +// elements to be joined, using the same formatting that `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 @@ -37,8 +37,8 @@ // // Example: // -// std::vector<string> v = {"foo", "bar", "baz"}; -// string s = absl::StrJoin(v, "-"); +// std::vector<std::string> v = {"foo", "bar", "baz"}; +// std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("foo-bar-baz", s); // // See comments on the `absl::StrJoin()` function for more examples. @@ -60,23 +60,23 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // ----------------------------------------------------------------------------- // 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 string. Formatters -// may be implemented as function objects, lambdas, or normal functions. You may -// provide your own Formatter to enable `absl::StrJoin()` to work with arbitrary -// types. +// argument as a string and appending it to a given output std::string. +// Formatters may be implemented as function objects, lambdas, or normal +// functions. You may provide your own Formatter to enable `absl::StrJoin()` to +// 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 string. +// `std::to_string()` to format an integer as a std::string. // // struct MyFormatter { -// void operator()(string* out, int i) const { +// void operator()(std::string* out, int i) const { // out->append(std::to_string(i)); // } // }; @@ -85,7 +85,7 @@ inline namespace lts_2018_12_18 { // argument to `absl::StrJoin()`: // // std::vector<int> v = {1, 2, 3, 4}; -// string s = absl::StrJoin(v, "-", MyFormatter()); +// std::string s = absl::StrJoin(v, "-", MyFormatter()); // EXPECT_EQ("1-2-3-4", s); // // The following standard formatters are provided within this file: @@ -157,7 +157,7 @@ DereferenceFormatter() { // StrJoin() // ----------------------------------------------------------------------------- // -// Joins a range of elements and returns the result as a string. +// Joins a range of elements and returns the result as a std::string. // `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. @@ -168,22 +168,22 @@ DereferenceFormatter() { // Example 1: // // Joins a collection of strings. This pattern also works with a collection // // of `absl::string_view` or even `const char*`. -// std::vector<string> v = {"foo", "bar", "baz"}; -// string s = absl::StrJoin(v, "-"); +// std::vector<std::string> v = {"foo", "bar", "baz"}; +// std::string s = 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 // // of ints or `absl::string_view` -- any `AlphaNum`-compatible type. -// string s = absl::StrJoin({"foo", "bar", "baz"}, "-"); +// std::string s = 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}; -// string s = absl::StrJoin(v, "-"); +// std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("1-2-3--4", s); // // Example 4: @@ -194,7 +194,7 @@ DereferenceFormatter() { // // `std::vector<int*>`. // int x = 1, y = 2, z = 3; // std::vector<int*> v = {&x, &y, &z}; -// string s = absl::StrJoin(v, "-"); +// std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("1-2-3", s); // // Example 5: @@ -203,65 +203,65 @@ DereferenceFormatter() { // v.emplace_back(new int(1)); // v.emplace_back(new int(2)); // v.emplace_back(new int(3)); -// string s = absl::StrJoin(v, "-"); +// std::string s = 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<>>`. -// std::map<string, int> m = { +// std::map<std::string, int> m = { // std::make_pair("a", 1), // std::make_pair("b", 2), // std::make_pair("c", 3)}; -// string s = absl::StrJoin(m, ",", absl::PairFormatter("=")); +// std::string s = absl::StrJoin(m, ",", absl::PairFormatter("=")); // EXPECT_EQ("a=1,b=2,c=3", s); // // Example 7: // // These examples show how `absl::StrJoin()` handles a few common edge // // cases: -// std::vector<string> v_empty; +// std::vector<std::string> v_empty; // EXPECT_EQ("", absl::StrJoin(v_empty, "-")); // -// std::vector<string> v_one_item = {"foo"}; +// std::vector<std::string> v_one_item = {"foo"}; // EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-")); // -// std::vector<string> v_empty_string = {""}; +// std::vector<std::string> v_empty_string = {""}; // EXPECT_EQ("", absl::StrJoin(v_empty_string, "-")); // -// std::vector<string> v_one_item_empty_string = {"a", ""}; +// std::vector<std::string> v_one_item_empty_string = {"a", ""}; // EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-")); // -// std::vector<string> v_two_empty_string = {"", ""}; +// std::vector<std::string> v_two_empty_string = {"", ""}; // EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-")); // // Example 8: // // Joins a `std::tuple<T...>` of heterogeneous types, converting each to -// // a string using the `absl::AlphaNum` class. -// string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); +// // a std::string using the `absl::AlphaNum` class. +// std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); // EXPECT_EQ("123-abc-0.456", s); template <typename Iterator, typename Formatter> std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, - Formatter&& fmt) { + Formatter&& fmt) { return strings_internal::JoinAlgorithm(start, end, sep, fmt); } template <typename Range, typename Formatter> std::string StrJoin(const Range& range, absl::string_view separator, - Formatter&& fmt) { + Formatter&& fmt) { return strings_internal::JoinRange(range, separator, fmt); } template <typename T, typename Formatter> std::string StrJoin(std::initializer_list<T> il, absl::string_view separator, - Formatter&& fmt) { + Formatter&& fmt) { return strings_internal::JoinRange(il, separator, fmt); } template <typename... T, typename Formatter> std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator, - Formatter&& fmt) { + Formatter&& fmt) { return strings_internal::JoinAlgorithm(value, separator, fmt); } @@ -276,16 +276,18 @@ std::string StrJoin(const Range& range, absl::string_view separator) { } template <typename T> -std::string StrJoin(std::initializer_list<T> il, absl::string_view separator) { +std::string StrJoin(std::initializer_list<T> il, + absl::string_view separator) { return strings_internal::JoinRange(il, separator); } template <typename... T> -std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator) { +std::string StrJoin(const std::tuple<T...>& value, + absl::string_view separator) { return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter()); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_STR_JOIN_H_ diff --git a/absl/strings/str_join_benchmark.cc b/absl/strings/str_join_benchmark.cc index 7fb0e497..d6f689ff 100644 --- a/absl/strings/str_join_benchmark.cc +++ b/absl/strings/str_join_benchmark.cc @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -58,7 +58,8 @@ void BM_Join2_KeysAndValues(benchmark::State& state) { const int string_len = state.range(0); const int num_pairs = state.range(1); const std::string s(string_len, 'x'); - const std::vector<std::pair<std::string, int>> v(num_pairs, std::make_pair(s, 42)); + const std::vector<std::pair<std::string, int>> v(num_pairs, + std::make_pair(s, 42)); for (auto _ : state) { std::string s = absl::StrJoin(v, ",", absl::PairFormatter("=")); benchmark::DoNotOptimize(s); diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc index c941f9c8..921d9c2b 100644 --- a/absl/strings/str_join_test.cc +++ b/absl/strings/str_join_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -118,7 +118,7 @@ TEST(StrJoin, APIExamples) { { // A std::map, which is a collection of std::pair<>s. - std::map<std::string, int> m = { {"a", 1}, {"b", 2}, {"c", 3} }; + std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}}; EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("="))); } @@ -140,7 +140,8 @@ TEST(StrJoin, APIExamples) { } { - // A range of 1 element gives a std::string with that element but no separator. + // A range of 1 element gives a std::string with that element but no + // separator. std::vector<std::string> v = {"foo"}; EXPECT_EQ("foo", absl::StrJoin(v, "-")); } @@ -173,9 +174,10 @@ TEST(StrJoin, APIExamples) { TEST(StrJoin, CustomFormatter) { std::vector<std::string> v{"One", "Two", "Three"}; { - std::string joined = absl::StrJoin(v, "", [](std::string* out, const std::string& in) { - absl::StrAppend(out, "(", in, ")"); - }); + std::string joined = + absl::StrJoin(v, "", [](std::string* out, const std::string& in) { + absl::StrAppend(out, "(", in, ")"); + }); EXPECT_EQ("(One)(Two)(Three)", joined); } { diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc index 72a0b584..3bd8bae1 100644 --- a/absl/strings/str_replace.cc +++ b/absl/strings/str_replace.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,7 +17,7 @@ #include "absl/strings/str_cat.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace strings_internal { using FixedMapping = @@ -69,13 +69,14 @@ int ApplySubstitutions( // aren't inlined. std::string StrReplaceAll(absl::string_view s, - strings_internal::FixedMapping replacements) { + strings_internal::FixedMapping replacements) { return StrReplaceAll<strings_internal::FixedMapping>(s, replacements); } -int StrReplaceAll(strings_internal::FixedMapping replacements, std::string* target) { +int StrReplaceAll(strings_internal::FixedMapping replacements, + std::string* target) { return StrReplaceAll<strings_internal::FixedMapping>(replacements, target); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/str_replace.h b/absl/strings/str_replace.h index a963f91e..cb995456 100644 --- a/absl/strings/str_replace.h +++ b/absl/strings/str_replace.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -29,12 +29,12 @@ // // Example: // -// string html_escaped = absl::StrReplaceAll(user_input, { -// {"&", "&"}, -// {"<", "<"}, -// {">", ">"}, -// {"\"", """}, -// {"'", "'"}}); +// std::string html_escaped = absl::StrReplaceAll(user_input, { +// {"&", "&"}, +// {"<", "<"}, +// {">", ">"}, +// {"\"", """}, +// {"'", "'"}}); #ifndef ABSL_STRINGS_STR_REPLACE_H_ #define ABSL_STRINGS_STR_REPLACE_H_ @@ -46,7 +46,7 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // StrReplaceAll() // @@ -59,10 +59,11 @@ inline namespace lts_2018_12_18 { // // Example: // -// string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", -// {{"$count", absl::StrCat(5)}, -// {"$who", "Bob"}, -// {"#Noun", "Apples"}}); +// std::string s = absl::StrReplaceAll( +// "$who bought $count #Noun. Thanks $who!", +// {{"$count", absl::StrCat(5)}, +// {"$who", "Bob"}, +// {"#Noun", "Apples"}}); // EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); ABSL_MUST_USE_RESULT std::string StrReplaceAll( absl::string_view s, @@ -79,20 +80,22 @@ ABSL_MUST_USE_RESULT std::string StrReplaceAll( // replacements["$who"] = "Bob"; // replacements["$count"] = "5"; // replacements["#Noun"] = "Apples"; -// string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", -// replacements); +// std::string s = 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. -// std::vector<std::pair<const absl::string_view, string>> replacements; +// std::vector<std::pair<const absl::string_view, std::string>> replacements; // replacements.push_back({"&", "&"}); // replacements.push_back({"<", "<"}); // replacements.push_back({">", ">"}); -// string s = absl::StrReplaceAll("if (ptr < &foo)", +// std::string s = absl::StrReplaceAll("if (ptr < &foo)", // replacements); // EXPECT_EQ("if (ptr < &foo)", s); template <typename StrToStrMapping> -std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements); +std::string StrReplaceAll(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 @@ -100,7 +103,7 @@ std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacemen // // Example: // -// string s = std::string("$who bought $count #Noun. Thanks $who!"); +// std::string s = std::string("$who bought $count #Noun. Thanks $who!"); // int count; // count = absl::StrReplaceAll({{"$count", absl::StrCat(5)}, // {"$who", "Bob"}, @@ -118,7 +121,7 @@ int StrReplaceAll( // // Example: // -// string s = std::string("if (ptr < &foo)"); +// std::string s = std::string("if (ptr < &foo)"); // int count = absl::StrReplaceAll({{"&", "&"}, // {"<", "<"}, // {">", ">"}}, &s); @@ -188,7 +191,8 @@ int ApplySubstitutions(absl::string_view s, } // namespace strings_internal template <typename StrToStrMapping> -std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements) { +std::string StrReplaceAll(absl::string_view s, + const StrToStrMapping& replacements) { auto subs = strings_internal::FindSubstitutions(s, replacements); std::string result; result.reserve(s.size()); @@ -209,7 +213,7 @@ int StrReplaceAll(const StrToStrMapping& replacements, std::string* target) { return substitutions; } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_STR_REPLACE_H_ diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc index 8386f2e6..95b2dc10 100644 --- a/absl/strings/str_replace_benchmark.cc +++ b/absl/strings/str_replace_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -54,7 +54,7 @@ void SetUpStrings() { size_t r = 0; big_string = new std::string(1000 * 1000, ' '); for (std::string phrase : {"the quick brown fox jumped over the lazy dogs", - "pack my box with the five dozen liquor jugs"}) { + "pack my box with the five dozen liquor jugs"}) { for (int i = 0; i < 10 * 1000; ++i) { r = r * 237 + 41; // not very random. memcpy(&(*big_string)[r % (big_string->size() - phrase.size())], @@ -108,11 +108,11 @@ void BM_StrReplaceAll(benchmark::State& state) { std::string src = *big_string; for (auto _ : state) { std::string dest = absl::StrReplaceAll(src, {{"the", "box"}, - {"brown", "quick"}, - {"jumped", "liquored"}, - {"dozen", "brown"}, - {"lazy", "pack"}, - {"liquor", "shakes"}}); + {"brown", "quick"}, + {"jumped", "liquored"}, + {"dozen", "brown"}, + {"lazy", "pack"}, + {"liquor", "shakes"}}); ABSL_RAW_CHECK(dest == *after_replacing_many, "not benchmarking intended behavior"); } diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc index 5d003a22..1ca23aff 100644 --- a/absl/strings/str_replace_test.cc +++ b/absl/strings/str_replace_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -148,7 +148,7 @@ TEST(StrReplaceAll, ManyReplacementsInMap) { replacements["$count"] = "5"; replacements["#Noun"] = "Apples"; std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", - replacements); + replacements); EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); } diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc index cd90425f..f1e03717 100644 --- a/absl/strings/str_split.cc +++ b/absl/strings/str_split.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -27,7 +27,7 @@ #include "absl/strings/ascii.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace { @@ -135,5 +135,5 @@ absl::string_view ByLength::Find(absl::string_view text, return absl::string_view(substr.data() + length_, 0); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h index 9483b30e..463ca008 100644 --- a/absl/strings/str_split.h +++ b/absl/strings/str_split.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -49,7 +49,7 @@ #include "absl/strings/strip.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { //------------------------------------------------------------------------------ // Delimiters @@ -72,23 +72,23 @@ inline namespace lts_2018_12_18 { // - `ByLength` // - `MaxSplits` // -// -// A Delimiter's Find() member function will be passed the input text that is to -// be split and the position to begin searching for the next delimiter in the -// input text. The returned absl::string_view should refer to the next -// occurrence (after pos) of the represented delimiter; this returned -// absl::string_view represents the next location where the input string should -// be broken. The returned 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 delimiter is found in the given text, a zero-length absl::string_view -// referring to text.end() should be returned (e.g., -// absl::string_view(text.end(), 0)). It is important that the returned -// absl::string_view always be within the bounds of input text given as an +// 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 absl::string_view should refer to the next occurrence +// (after `pos`) of the represented delimiter; this returned absl::string_view +// represents the next location where the input `text` should be broken. +// +// The returned 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 +// delimiter is found in the input `text`, a zero-length absl::string_view +// referring to `text.end()` should be returned (e.g., +// `text.substr(text.size())`). It is important that the returned +// 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() +// single char and will look for that char in the text passed to the `Find()` // function: // // struct SimpleDelimiter { @@ -97,9 +97,9 @@ inline namespace lts_2018_12_18 { // absl::string_view Find(absl::string_view text, size_t pos) { // auto found = text.find(c_, pos); // if (found == absl::string_view::npos) -// return absl::string_view(text.end(), 0); +// return text.substr(text.size()); // -// return absl::string_view(text, found, 1); +// return text.substr(found, 1); // } // }; @@ -132,8 +132,7 @@ class ByString { // ByChar // // A single character delimiter. `ByChar` is functionally equivalent to a -// 1-char string within a `ByString` delimiter, but slightly more -// efficient. +// 1-char string within a `ByString` delimiter, but slightly more efficient. // // Example: // @@ -414,10 +413,10 @@ struct SkipWhitespace { // // The `StrSplit()` function adapts the returned collection to the collection // specified by the caller (e.g. `std::vector` above). The returned collections -// may contain `string`, `absl::string_view` (in which case the original string -// being split must ensure that it outlives the collection), or any object that -// can be explicitly created from an `absl::string_view`. This behavior works -// for: +// may contain `std::string`, `absl::string_view` (in which case the original +// string being split must ensure that it outlives the collection), or any +// object that can be explicitly created from an `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` @@ -461,7 +460,7 @@ struct SkipWhitespace { // Example: // // // Stores first two split strings as the members in a std::pair. -// std::pair<string, string> p = absl::StrSplit("a,b,c", ','); +// std::pair<std::string, std::string> p = 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 @@ -471,7 +470,7 @@ struct SkipWhitespace { // // // The input string "a=b=c,d=e,f=,g" becomes // // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" } -// std::map<string, string> m; +// std::map<std::string, std::string> m; // for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) { // m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1))); // } @@ -508,7 +507,7 @@ StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d, std::move(text), DelimiterType(d), std::move(p)); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_STR_SPLIT_H_ diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc index 0ac297c8..f38dfcfe 100644 --- a/absl/strings/str_split_benchmark.cc +++ b/absl/strings/str_split_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -44,6 +44,29 @@ void BM_Split2StringView(benchmark::State& state) { } BENCHMARK_RANGE(BM_Split2StringView, 0, 1 << 20); +static const absl::string_view kDelimiters = ";:,."; + +std::string MakeMultiDelimiterTestString(int desired_length) { + static const int kAverageValueLen = 25; + std::string test(desired_length * kAverageValueLen, 'x'); + for (int i = 0; i * kAverageValueLen < test.size(); ++i) { + // Cycle through a variety of delimiters. + test[i * kAverageValueLen] = kDelimiters[i % kDelimiters.size()]; + } + return test; +} + +// Measure StrSplit with ByAnyChar with four delimiters to choose from. +void BM_Split2StringViewByAnyChar(benchmark::State& state) { + std::string test = MakeMultiDelimiterTestString(state.range(0)); + for (auto _ : state) { + std::vector<absl::string_view> result = + absl::StrSplit(test, absl::ByAnyChar(kDelimiters)); + benchmark::DoNotOptimize(result); + } +} +BENCHMARK_RANGE(BM_Split2StringViewByAnyChar, 0, 1 << 20); + void BM_Split2StringViewLifted(benchmark::State& state) { std::string test = MakeTestString(state.range(0)); std::vector<absl::string_view> result; @@ -69,7 +92,8 @@ BENCHMARK_RANGE(BM_Split2String, 0, 1 << 20); void BM_Split2SplitStringUsing(benchmark::State& state) { std::string test = MakeTestString(state.range(0)); for (auto _ : state) { - std::vector<std::string> result = absl::StrSplit(test, ';', absl::SkipEmpty()); + std::vector<std::string> result = + absl::StrSplit(test, ';', absl::SkipEmpty()); benchmark::DoNotOptimize(result); } } diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc index caa88277..02f27bc4 100644 --- a/absl/strings/str_split_test.cc +++ b/absl/strings/str_split_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -40,8 +40,8 @@ using ::testing::UnorderedElementsAre; TEST(Split, TraitsTest) { static_assert(!absl::strings_internal::SplitterIsConvertibleTo<int>::value, ""); - static_assert(!absl::strings_internal::SplitterIsConvertibleTo<std::string>::value, - ""); + static_assert( + !absl::strings_internal::SplitterIsConvertibleTo<std::string>::value, ""); static_assert(absl::strings_internal::SplitterIsConvertibleTo< std::vector<std::string>>::value, ""); @@ -71,8 +71,8 @@ TEST(Split, TraitsTest) { // namespaces just like callers will need to use. TEST(Split, APIExamples) { { - // Passes std::string delimiter. Assumes the default of Literal. - std::vector<std::string> v = absl::StrSplit("a,b,c", ','); + // Passes std::string delimiter. Assumes the default of ByString. + std::vector<std::string> v = absl::StrSplit("a,b,c", ","); // NOLINT EXPECT_THAT(v, ElementsAre("a", "b", "c")); // Equivalent to... @@ -97,17 +97,6 @@ TEST(Split, APIExamples) { } { - // Same as above, but using std::string - std::vector<std::string> v = absl::StrSplit("a,b,c", ','); - EXPECT_THAT(v, ElementsAre("a", "b", "c")); - - // Equivalent to... - using absl::ByChar; - v = absl::StrSplit("a,b,c", ByChar(',')); - EXPECT_THAT(v, ElementsAre("a", "b", "c")); - } - - { // Uses the Literal std::string "=>" as the delimiter. const std::vector<std::string> v = absl::StrSplit("a=>b=>c", "=>"); EXPECT_THAT(v, ElementsAre("a", "b", "c")); @@ -182,7 +171,8 @@ TEST(Split, APIExamples) { { // Uses the SkipWhitespace predicate. using absl::SkipWhitespace; - std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipWhitespace()); + std::vector<std::string> v = + absl::StrSplit(" a , ,,b,", ',', SkipWhitespace()); EXPECT_THAT(v, ElementsAre(" a ", "b")); } @@ -215,7 +205,8 @@ TEST(Split, APIExamples) { { // Results stored in a std::multimap. - std::multimap<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ','); + std::multimap<std::string, std::string> m = + absl::StrSplit("a,1,b,2,a,3", ','); EXPECT_EQ(3, m.size()); auto it = m.find("a"); EXPECT_EQ("1", it->second); @@ -271,7 +262,8 @@ TEST(SplitIterator, Basics) { EXPECT_EQ("a", *it); // tests dereference ++it; // tests preincrement EXPECT_NE(it, end); - EXPECT_EQ("b", std::string(it->data(), it->size())); // tests dereference as ptr + EXPECT_EQ("b", + std::string(it->data(), it->size())); // tests dereference as ptr it++; // tests postincrement EXPECT_EQ(it, end); } @@ -295,7 +287,8 @@ TEST(SplitIterator, Predicate) { EXPECT_EQ("a", *it); // tests dereference ++it; // tests preincrement -- "b" should be skipped here. EXPECT_NE(it, end); - EXPECT_EQ("c", std::string(it->data(), it->size())); // tests dereference as ptr + EXPECT_EQ("c", + std::string(it->data(), it->size())); // tests dereference as ptr it++; // tests postincrement EXPECT_EQ(it, end); } @@ -421,10 +414,13 @@ TEST(Splitter, ConversionOperator) { TestMapConversionOperator<std::map<std::string, std::string>>(splitter); TestMapConversionOperator< std::multimap<absl::string_view, absl::string_view>>(splitter); - TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(splitter); - TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(splitter); + TestMapConversionOperator<std::multimap<absl::string_view, std::string>>( + splitter); + TestMapConversionOperator<std::multimap<std::string, absl::string_view>>( + splitter); TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter); - TestMapConversionOperator<std::unordered_map<std::string, std::string>>(splitter); + TestMapConversionOperator<std::unordered_map<std::string, std::string>>( + splitter); // Tests conversion to std::pair @@ -568,10 +564,9 @@ TEST(Split, AcceptsCertainTemporaries) { } TEST(Split, Temporary) { - // Use a std::string longer than the small-std::string-optimization length, so that when - // the temporary is destroyed, if the splitter keeps a reference to the - // std::string's contents, it'll reference freed memory instead of just dead - // on-stack memory. + // Use a std::string longer than the SSO length, so that when the temporary is + // destroyed, if the splitter keeps a reference to the std::string's contents, + // it'll reference freed memory instead of just dead on-stack memory. const char input[] = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u"; EXPECT_LT(sizeof(std::string), ABSL_ARRAYSIZE(input)) << "Input should be larger than fits on the stack."; @@ -647,6 +642,11 @@ TEST(Split, StringDelimiter) { } } +#if !defined(__cpp_char8_t) +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++2a-compat" +#endif TEST(Split, UTF8) { // Tests splitting utf8 strings and utf8 delimiters. std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5"; @@ -673,6 +673,10 @@ TEST(Split, UTF8) { EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere")); } } +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#endif // !defined(__cpp_char8_t) TEST(Split, EmptyStringDelimiter) { { @@ -782,7 +786,7 @@ static bool IsFoundAt(absl::string_view text, Delimiter d, int expected_pos) { } // -// Tests for Literal +// Tests for ByString // // Tests using any delimiter that represents a single comma. @@ -802,7 +806,7 @@ void TestComma(Delimiter d) { EXPECT_FALSE(IsFoundAt(";", d, -1)); } -TEST(Delimiter, Literal) { +TEST(Delimiter, ByString) { using absl::ByString; TestComma(ByString(",")); diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc index 3620ff44..9d241e51 100644 --- a/absl/strings/string_view.cc +++ b/absl/strings/string_view.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -24,7 +24,7 @@ #include "absl/strings/internal/memutil.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace { void WritePadding(std::ostream& o, size_t pad) { @@ -78,18 +78,6 @@ std::ostream& operator<<(std::ostream& o, string_view piece) { return o; } -string_view::size_type string_view::copy(char* buf, size_type n, - size_type pos) const { - size_type ulen = length_; - assert(pos <= ulen); - size_type rlen = std::min(ulen - pos, n); - if (rlen > 0) { - const char* start = ptr_ + pos; - std::copy(start, start + rlen, buf); - } - return rlen; -} - string_view::size_type string_view::find(string_view s, size_type pos) const noexcept { if (empty() || pos > length_) { @@ -229,7 +217,7 @@ string_view::size_type string_view::find_last_not_of(char c, // 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 http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx +// at https://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx #ifdef _MSC_VER #define ABSL_STRING_VIEW_SELECTANY __declspec(selectany) #else @@ -241,7 +229,7 @@ constexpr string_view::size_type string_view::npos; ABSL_STRING_VIEW_SELECTANY constexpr string_view::size_type string_view::kMaxSize; -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_HAVE_STD_STRING_VIEW diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index df6f1ae4..3a0a4609 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -32,12 +32,12 @@ #ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> +#include <string_view> // IWYU pragma: export namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { using std::string_view; -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #else // ABSL_HAVE_STD_STRING_VIEW @@ -52,10 +52,11 @@ using std::string_view; #include "absl/base/internal/throw_delegate.h" #include "absl/base/macros.h" +#include "absl/base/optimization.h" #include "absl/base/port.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // absl::string_view // @@ -104,7 +105,6 @@ inline namespace lts_2018_12_18 { // example, when splitting a string, `std::vector<absl::string_view>` is a // natural data type for the output. // -// // When constructed from a source which is nul-terminated, the `string_view` // 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 @@ -176,19 +176,9 @@ class string_view { // Implicit constructor of a `string_view` from nul-terminated `str`. When // accepting possibly null strings, use `absl::NullSafeStringView(str)` // instead (see below). -#if 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. constexpr string_view(const char* str) // NOLINT(runtime/explicit) : ptr_(str), - length_(CheckLengthInternal(str ? __builtin_strlen(str) : 0)) {} -#else - constexpr string_view(const char* str) // NOLINT(runtime/explicit) - : ptr_(str), length_(CheckLengthInternal(str ? strlen(str) : 0)) {} -#endif + length_(str ? CheckLengthInternal(StrlenInternal(str)) : 0) {} // Implicit constructor of a `string_view` from a `const char*` and length. constexpr string_view(const char* data, size_type len) @@ -280,7 +270,7 @@ class string_view { // Checks if the `string_view` is empty (refers to no characters). constexpr bool empty() const noexcept { return length_ == 0; } - // std::string:view::operator[] + // string_view::operator[] // // Returns the ith element of an `string_view` using the array operator. // Note that this operator does not perform any bounds checking. @@ -348,7 +338,17 @@ class string_view { // // 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; + size_type copy(char* buf, size_type n, size_type pos = 0) const { + if (ABSL_PREDICT_FALSE(pos > length_)) { + base_internal::ThrowStdOutOfRange("absl::string_view::copy"); + } + size_type rlen = (std::min)(length_ - pos, n); + if (rlen > 0) { + const char* start = ptr_ + pos; + std::copy(start, start + rlen, buf); + } + return rlen; + } // string_view::substr() // @@ -358,7 +358,7 @@ class string_view { string_view substr(size_type pos, size_type n = npos) const { if (ABSL_PREDICT_FALSE(pos > length_)) base_internal::ThrowStdOutOfRange("absl::string_view::substr"); - n = std::min(n, length_ - pos); + n = (std::min)(n, length_ - pos); return string_view(ptr_ + pos, n); } @@ -371,7 +371,7 @@ class string_view { // on the respective sizes of the two `string_view`s to determine which is // smaller, equal, or greater. int compare(string_view x) const noexcept { - auto min_length = std::min(length_, x.length_); + auto min_length = (std::min)(length_, x.length_); if (min_length > 0) { int r = memcmp(ptr_, x.ptr_, min_length); if (r < 0) return -1; @@ -499,6 +499,24 @@ class string_view { return ABSL_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 + } + const char* ptr_; size_type length_; }; @@ -511,6 +529,7 @@ inline bool operator==(string_view x, string_view y) noexcept { if (len != y.size()) { return false; } + return x.data() == y.data() || len <= 0 || memcmp(x.data(), y.data(), len) == 0; } @@ -520,7 +539,7 @@ inline bool operator!=(string_view x, string_view y) noexcept { } inline bool operator<(string_view x, string_view y) noexcept { - auto min_size = std::min(x.size(), y.size()); + auto min_size = (std::min)(x.size(), y.size()); const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size); return (r < 0) || (r == 0 && x.size() < y.size()); } @@ -538,13 +557,13 @@ inline bool operator>=(string_view x, string_view y) noexcept { // IO Insertion Operator std::ostream& operator<<(std::ostream& o, string_view piece); -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_HAVE_STD_STRING_VIEW namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // ClippedSubstr() // @@ -552,7 +571,7 @@ inline namespace lts_2018_12_18 { // 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())); + pos = (std::min)(pos, static_cast<size_t>(s.size())); return s.substr(pos, n); } @@ -565,7 +584,7 @@ inline string_view NullSafeStringView(const char* p) { return p ? string_view(p) : string_view(); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_STRING_VIEW_H_ diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc index f4420320..46909cb0 100644 --- a/absl/strings/string_view_benchmark.cc +++ b/absl/strings/string_view_benchmark.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index ed34ed83..22d43536 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -284,9 +284,10 @@ TEST(StringViewTest, ComparisonOperatorsByCharacterPosition) { } #undef COMPARE -// Sadly, our users often confuse string::npos with absl::string_view::npos; -// So much so that we test here that they are the same. They need to -// both be unsigned, and both be the maximum-valued integer of their type. +// Sadly, our users often confuse std::string::npos with +// absl::string_view::npos; So much so that we test here that they are the same. +// They need to both be unsigned, and both be the maximum-valued integer of +// their type. template <typename T> struct is_type { @@ -368,6 +369,11 @@ TEST(StringViewTest, STL1) { EXPECT_EQ(buf[1], c[1]); EXPECT_EQ(buf[2], c[2]); EXPECT_EQ(buf[3], a[3]); +#ifdef ABSL_HAVE_EXCEPTIONS + EXPECT_THROW(a.copy(buf, 1, 27), std::out_of_range); +#else + EXPECT_DEATH(a.copy(buf, 1, 27), "absl::string_view::copy"); +#endif } // Separated from STL1() because some compilers produce an overly @@ -755,7 +761,6 @@ TEST(StringViewTest, Remove) { std::string s1("123"); s1 += '\0'; s1 += "456"; - absl::string_view b(s1); absl::string_view e; std::string s2; @@ -941,6 +946,11 @@ TEST(StringViewTest, ConstexprCompiles) { #error GCC/clang should have constexpr string_view. #endif +// MSVC 2017+ should be able to construct a constexpr string_view from a cstr. +#if defined(_MSC_VER) && _MSC_VER >= 1910 +#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1 +#endif + #endif // ABSL_HAVE_STD_STRING_VIEW #ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR @@ -995,8 +1005,8 @@ TEST(StringViewTest, ConstexprCompiles) { TEST(StringViewTest, Noexcept) { EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view, const std::string&>::value)); - EXPECT_TRUE( - (std::is_nothrow_constructible<absl::string_view, const std::string&>::value)); + EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view, + const std::string&>::value)); EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value); constexpr absl::string_view sp; EXPECT_TRUE(noexcept(sp.begin())); diff --git a/absl/strings/strip.h b/absl/strings/strip.h index 059f57b7..8e2ae422 100644 --- a/absl/strings/strip.h +++ b/absl/strings/strip.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -30,7 +30,7 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { // ConsumePrefix() // @@ -85,7 +85,7 @@ ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix( return str; } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_STRIP_H_ diff --git a/absl/strings/strip_test.cc b/absl/strings/strip_test.cc index 40c4c607..e4e00cb6 100644 --- a/absl/strings/strip_test.cc +++ b/absl/strings/strip_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -27,9 +27,6 @@ namespace { -using testing::ElementsAre; -using testing::IsEmpty; - TEST(Strip, ConsumePrefixOneChar) { absl::string_view input("abc"); EXPECT_TRUE(absl::ConsumePrefix(&input, "a")); diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc index b70e70e8..6bc9641d 100644 --- a/absl/strings/substitute.cc +++ b/absl/strings/substitute.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -23,7 +23,7 @@ #include "absl/strings/string_view.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace substitute_internal { void SubstituteAndAppendArray(std::string* output, absl::string_view format, @@ -168,5 +168,5 @@ Arg::Arg(Dec dec) { } } // namespace substitute_internal -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index 43d73ad7..3ba7f4d3 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -35,19 +35,21 @@ // 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: -// string s = Substitute("$1 purchased $0 $2. Thanks $1!", -// 5, "Bob", "Apples"); -// EXPECT_EQ("Bob purchased 5 Apples. Thanks Bob!", s); +// std::string 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: -// string s = "Hi. "; +// std::string 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: -// * absl::string_view, string, const char* (null is equivalent to "") +// * absl::string_view, std::string, const char* (null is equivalent to "") // * int32_t, int64_t, uint32_t, uint64 // * float, double // * bool (Printed as "true" or "false") @@ -70,6 +72,8 @@ #include <cstring> #include <string> +#include <type_traits> +#include <vector> #include "absl/base/macros.h" #include "absl/base/port.h" @@ -82,7 +86,7 @@ #include "absl/strings/strip.h" namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { namespace substitute_internal { // Arg @@ -153,6 +157,17 @@ class Arg { 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, + 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) @@ -457,7 +472,7 @@ void SubstituteAndAppend( // Example: // template <typename... Args> // void VarMsg(absl::string_view format, const Args&... args) { -// string s = absl::Substitute(format, args...); +// std::string s = absl::Substitute(format, args...); ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) { std::string result; @@ -575,70 +590,70 @@ std::string Substitute(const char* format, const substitute_internal::Arg& a0) "contains one of $1-$9"); std::string 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 std::string is either missing its $0/$1, or " "contains one of $2-$9"); std::string 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 std::string is either missing its $0/$1/$2, or " "contains one of $3-$9"); std::string 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 std::string is either missing its $0-$3, or " "contains one of $4-$9"); std::string 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 std::string is either missing its $0-$4, or " "contains one of $5-$9"); std::string 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 std::string is either missing its $0-$5, or " "contains one of $6-$9"); std::string 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 std::string is either missing its $0-$6, or " "contains one of $7-$9"); std::string 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 std::string is either missing its $0-$7, or " @@ -667,7 +682,7 @@ std::string Substitute( "format std::string doesn't contain all of $0 through $9"); #endif // ABSL_BAD_CALL_IF -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl #endif // ABSL_STRINGS_SUBSTITUTE_H_ diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc index 144df01e..e27abb17 100644 --- a/absl/strings/substitute_test.cc +++ b/absl/strings/substitute_test.cc @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -15,6 +15,7 @@ #include "absl/strings/substitute.h" #include <cstdint> +#include <vector> #include "gtest/gtest.h" #include "absl/strings/str_cat.h" @@ -172,6 +173,17 @@ TEST(SubstituteTest, SubstituteAndAppend) { EXPECT_EQ("a b c d e f g h i j", str); } +TEST(SubstituteTest, VectorBoolRef) { + std::vector<bool> v = {true, false}; + const auto& cv = v; + EXPECT_EQ("true false true false", + absl::Substitute("$0 $1 $2 $3", v[0], v[1], cv[0], cv[1])); + + std::string str = "Logic be like: "; + absl::SubstituteAndAppend(&str, "$0 $1 $2 $3", v[0], v[1], cv[0], cv[1]); + EXPECT_EQ("Logic be like: true false true false", str); +} + #ifdef GTEST_HAS_DEATH_TEST TEST(SubstituteDeathTest, SubstituteDeath) { |