Commit b35973e3 by Abseil Team Committed by Mark Barolak

Export of internal Abseil changes

--
d857e6e1f9b09a3eb5abd890677a98b23346f07a by Abseil Team <absl-team@google.com>:

Simplify internal TryAcquireWithSpinning.

No point declaring the `result` variable: we can just return the results
directly.

PiperOrigin-RevId: 307045800

--
421952252bc23be51f47f7d23f3422bad1ed382c by Derek Mauro <dmauro@google.com>:

Add custom sink support for `absl::Format()` through an ADL extension mechanism.

Users can now define
`void AbslFormatFlush(MySink* dest, absl::string_view part)`
to allow `absl::Format()` to append to a custom sink.

PiperOrigin-RevId: 306929052

--
c73d5cdb62cd58ea421ed1aeeab78a0ffcfeeefb by Matt Calabrese <calabrese@google.com>:

Internal-only conformance-testing macro ABSL_INTERNAL_ASSERT_CONFORMANCE_OF for compile-time and runtime checks of a specified type, expected properties of that type, and a logically-ordered series of equivalence classes of that type.

PiperOrigin-RevId: 306885512

--
a8c2495a07f37d68907855e3f0535bd5c27a3b52 by Abseil Team <absl-team@google.com>:

Internal change

PiperOrigin-RevId: 306766753
GitOrigin-RevId: d857e6e1f9b09a3eb5abd890677a98b23346f07a
Change-Id: Ic23c92ac74f9ffcbb2471ff8c6691f4b7b20354b
parent db5773a7
...@@ -294,6 +294,8 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -294,6 +294,8 @@ set(ABSL_INTERNAL_DLL_FILES
"types/internal/conformance_aliases.h" "types/internal/conformance_aliases.h"
"types/internal/conformance_archetype.h" "types/internal/conformance_archetype.h"
"types/internal/conformance_profile.h" "types/internal/conformance_profile.h"
"types/internal/parentheses.h"
"types/internal/transform_args.h"
"types/internal/variant.h" "types/internal/variant.h"
"types/optional.h" "types/optional.h"
"types/internal/optional.h" "types/internal/optional.h"
......
...@@ -651,6 +651,7 @@ cc_test( ...@@ -651,6 +651,7 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":cord",
":str_format", ":str_format",
":strings", ":strings",
"//absl/base:core_headers", "//absl/base:core_headers",
...@@ -666,8 +667,10 @@ cc_test( ...@@ -666,8 +667,10 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":cord",
":str_format", ":str_format",
":str_format_internal", ":str_format_internal",
":strings",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
...@@ -726,6 +729,7 @@ cc_test( ...@@ -726,6 +729,7 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":cord",
":str_format_internal", ":str_format_internal",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
......
...@@ -409,6 +409,7 @@ absl_cc_test( ...@@ -409,6 +409,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::str_format absl::str_format
absl::cord
absl::strings absl::strings
absl::core_headers absl::core_headers
gmock_main gmock_main
...@@ -424,6 +425,8 @@ absl_cc_test( ...@@ -424,6 +425,8 @@ absl_cc_test(
DEPS DEPS
absl::str_format absl::str_format
absl::str_format_internal absl::str_format_internal
absl::cord
absl::strings
gmock_main gmock_main
) )
...@@ -487,6 +490,7 @@ absl_cc_test( ...@@ -487,6 +490,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::str_format_internal absl::str_format_internal
absl::cord
gmock_main gmock_main
) )
......
...@@ -19,9 +19,27 @@ ...@@ -19,9 +19,27 @@
#include <random> #include <random>
#include <string> #include <string>
#include "absl/strings/cord.h"
#include "gtest/gtest.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "gtest/gtest.h" namespace my_namespace {
class UserDefinedType {
public:
UserDefinedType() = default;
void Append(absl::string_view str) { value_.append(str.data(), str.size()); }
const std::string& Value() const { return value_; }
friend void AbslFormatFlush(UserDefinedType* x, absl::string_view str) {
x->Append(str);
}
private:
std::string value_;
};
} // namespace my_namespace
namespace { namespace {
...@@ -63,4 +81,21 @@ TEST(FormatExtensionTest, SinkAppendChars) { ...@@ -63,4 +81,21 @@ TEST(FormatExtensionTest, SinkAppendChars) {
EXPECT_EQ(actual, expected); EXPECT_EQ(actual, expected);
} }
} }
TEST(FormatExtensionTest, CordSink) {
absl::Cord c;
absl::Format(&c, "There were %04d little %s.", 3, "pigs");
EXPECT_EQ(c, "There were 0003 little pigs.");
absl::Format(&c, "And %-3llx bad wolf!", 1);
EXPECT_EQ(c, "There were 0003 little pigs.And 1 bad wolf!");
}
TEST(FormatExtensionTest, CustomSink) {
my_namespace::UserDefinedType sink;
absl::Format(&sink, "There were %04d little %s.", 3, "pigs");
EXPECT_EQ("There were 0003 little pigs.", sink.Value());
absl::Format(&sink, "And %-3llx bad wolf!", 1);
EXPECT_EQ("There were 0003 little pigs.And 1 bad wolf!", sink.Value());
}
} // namespace } // namespace
...@@ -91,10 +91,11 @@ inline void AbslFormatFlush(BufferRawSink* sink, string_view v) { ...@@ -91,10 +91,11 @@ inline void AbslFormatFlush(BufferRawSink* sink, string_view v) {
sink->Write(v); sink->Write(v);
} }
// This is a SFINAE to get a better compiler error message when the type
// is not supported.
template <typename T> template <typename T>
auto InvokeFlush(T* out, string_view s) auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) {
-> decltype(str_format_internal::AbslFormatFlush(out, s)) { AbslFormatFlush(out, s);
str_format_internal::AbslFormatFlush(out, s);
} }
} // namespace str_format_internal } // namespace str_format_internal
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/strings/cord.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
...@@ -37,6 +38,12 @@ TEST(InvokeFlush, Stream) { ...@@ -37,6 +38,12 @@ TEST(InvokeFlush, Stream) {
EXPECT_EQ(str.str(), "ABCDEF"); EXPECT_EQ(str.str(), "ABCDEF");
} }
TEST(InvokeFlush, Cord) {
absl::Cord str("ABC");
str_format_internal::InvokeFlush(&str, "DEF");
EXPECT_EQ(str, "ABCDEF");
}
TEST(BufferRawSink, Limits) { TEST(BufferRawSink, Limits) {
char buf[16]; char buf[16];
{ {
...@@ -70,4 +77,3 @@ TEST(BufferRawSink, Limits) { ...@@ -70,4 +77,3 @@ TEST(BufferRawSink, Limits) {
} // namespace } // namespace
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
...@@ -57,8 +57,7 @@ ...@@ -57,8 +57,7 @@
// arbitrary sink types: // arbitrary sink types:
// //
// * A generic `Format()` function to write outputs to arbitrary sink types, // * A generic `Format()` function to write outputs to arbitrary sink types,
// which must implement a `RawSinkFormat` interface. (See // which must implement a `FormatRawSink` interface.
// `str_format_sink.h` for more information.)
// //
// * A `FormatUntyped()` function that is similar to `Format()` except it is // * A `FormatUntyped()` function that is similar to `Format()` except it is
// loosely typed. `FormatUntyped()` is not a template and does not perform // loosely typed. `FormatUntyped()` is not a template and does not perform
...@@ -432,6 +431,16 @@ int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format, ...@@ -432,6 +431,16 @@ int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format,
// //
// FormatRawSink is a type erased wrapper around arbitrary sink objects // FormatRawSink is a type erased wrapper around arbitrary sink objects
// specifically used as an argument to `Format()`. // specifically used as an argument to `Format()`.
//
// All the object has to do define an overload of `AbslFormatFlush()` for the
// sink, usually by adding a ADL-based free function in the same namespace as
// the sink:
//
// void AbslFormatFlush(MySink* dest, absl::string_view part);
//
// where `dest` is the pointer passed to `absl::Format()`. The function should
// append `part` to `dest`.
//
// FormatRawSink does not own the passed sink object. The passed object must // FormatRawSink does not own the passed sink object. The passed object must
// outlive the FormatRawSink. // outlive the FormatRawSink.
class FormatRawSink { class FormatRawSink {
...@@ -455,12 +464,13 @@ class FormatRawSink { ...@@ -455,12 +464,13 @@ class FormatRawSink {
// `absl::FormatRawSink` interface), using a format string and zero or more // `absl::FormatRawSink` interface), using a format string and zero or more
// additional arguments. // additional arguments.
// //
// By default, `std::string` and `std::ostream` are supported as destination // By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as
// objects. If a `std::string` is used the formatted string is appended to it. // 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 // `absl::Format()` is a generic version of `absl::StrAppendFormat()`, for
// sinks. The format string, like format strings for `StrFormat()`, is checked // custom sinks. The format string, like format strings for `StrFormat()`, is
// at compile-time. // checked at compile-time.
// //
// On failure, this function returns `false` and the state of the sink is // On failure, this function returns `false` and the state of the sink is
// unspecified. // unspecified.
......
...@@ -1439,20 +1439,18 @@ void Mutex::AssertNotHeld() const { ...@@ -1439,20 +1439,18 @@ void Mutex::AssertNotHeld() const {
// may spin for a short while if the lock cannot be acquired immediately. // may spin for a short while if the lock cannot be acquired immediately.
static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) { static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) {
int c = mutex_globals.spinloop_iterations; int c = mutex_globals.spinloop_iterations;
int result = -1; // result of operation: 0=false, 1=true, -1=unknown
do { // do/while somewhat faster on AMD do { // do/while somewhat faster on AMD
intptr_t v = mu->load(std::memory_order_relaxed); intptr_t v = mu->load(std::memory_order_relaxed);
if ((v & (kMuReader|kMuEvent)) != 0) { // a reader or tracing -> give up if ((v & (kMuReader|kMuEvent)) != 0) {
result = 0; return false; // a reader or tracing -> give up
} else if (((v & kMuWriter) == 0) && // no holder -> try to acquire } else if (((v & kMuWriter) == 0) && // no holder -> try to acquire
mu->compare_exchange_strong(v, kMuWriter | v, mu->compare_exchange_strong(v, kMuWriter | v,
std::memory_order_acquire, std::memory_order_acquire,
std::memory_order_relaxed)) { std::memory_order_relaxed)) {
result = 1; return true;
} }
} while (result == -1 && --c > 0); } while (--c > 0);
return result == 1; return false;
} }
ABSL_XRAY_LOG_ARGS(1) void Mutex::Lock() { ABSL_XRAY_LOG_ARGS(1) void Mutex::Lock() {
......
...@@ -216,11 +216,15 @@ cc_library( ...@@ -216,11 +216,15 @@ cc_library(
"internal/conformance_aliases.h", "internal/conformance_aliases.h",
"internal/conformance_archetype.h", "internal/conformance_archetype.h",
"internal/conformance_profile.h", "internal/conformance_profile.h",
"internal/conformance_testing.h",
"internal/conformance_testing_helpers.h",
"internal/parentheses.h",
"internal/transform_args.h",
], ],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
"//absl/debugging:demangle_internal", "//absl/algorithm:container",
"//absl/meta:type_traits", "//absl/meta:type_traits",
"//absl/strings", "//absl/strings",
"//absl/utility", "//absl/utility",
......
...@@ -246,9 +246,14 @@ absl_cc_library( ...@@ -246,9 +246,14 @@ absl_cc_library(
"internal/conformance_aliases.h" "internal/conformance_aliases.h"
"internal/conformance_archetype.h" "internal/conformance_archetype.h"
"internal/conformance_profile.h" "internal/conformance_profile.h"
"internal/conformance_testing.h",
"internal/conformance_testing_helpers.h",
"internal/parentheses.h",
"internal/transform_args.h",
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::algorithm
absl::debugging absl::debugging
absl::type_traits absl::type_traits
absl::strings absl::strings
...@@ -282,6 +287,7 @@ absl_cc_test( ...@@ -282,6 +287,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::conformance_testing absl::conformance_testing
absl::type_traits
gmock_main gmock_main
) )
......
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// parentheses.h
// -----------------------------------------------------------------------------
//
// This file contains macros that expand to a left parenthesis and a right
// parenthesis. These are in their own file and are generated from macros
// because otherwise clang-format gets confused and clang-format off directives
// do not help.
//
// The parentheses macros are used when wanting to require a rescan before
// expansion of parenthesized text appearing after a function-style macro name.
#ifndef ABSL_TYPES_INTERNAL_PARENTHESES_H_
#define ABSL_TYPES_INTERNAL_PARENTHESES_H_
#define ABSL_INTERNAL_LPAREN (
#define ABSL_INTERNAL_RPAREN )
#endif // ABSL_TYPES_INTERNAL_PARENTHESES_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment