Commit fbdff6f3 by Abseil Team Committed by Andy Getz

Export of internal Abseil changes

--
ff793052bd01e1e4fcf639f94d7c30c4855a9372 by Evan Brown <ezb@google.com>:

Roll forward of btree_iterator refactoring.

PiperOrigin-RevId: 346116047

--
17984679f16e3e2139b0f14fa76f4a6ca16a3ef9 by Chris Kennelly <ckennelly@google.com>:

Extend absl::StrContains to accept single character needles.

Single characters are more efficient to search for.  Extending this API allows
the abseil-string-find-str-contains Clang Tidy to include this pattern.

The C++ committee has adopted http://wg21.link/P1679 for inclusion in C++23.

PiperOrigin-RevId: 346095060

--
ef20b31c501b1dcaa25e244fd8f8aa43dec09bd6 by Jorg Brown <jorg@google.com>:

Internal change for cord ring

PiperOrigin-RevId: 346087545

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

Release layout_benchmark

PiperOrigin-RevId: 345968909

--
3a0eda337ee43622f92cfe14c2aa06f72dc71ee5 by Derek Mauro <dmauro@google.com>:

Release raw_hash_set_probe_benchmark

PiperOrigin-RevId: 345965969

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

Internal change

PiperOrigin-RevId: 345733599

--
7c9e24a71188df945be17fe98f700bdb51f81b16 by Derek Mauro <dmauro@google.com>:

Release hash_benchmark

PiperOrigin-RevId: 345721635

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

Release raw_hash_set_benchmark

PiperOrigin-RevId: 345708384

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

Updates the implementation of InlinedVector to accurately express the value-initialization semantics of the default constructor

PiperOrigin-RevId: 345548260

--
1532424deda97d468444c217cc0fa4614099c7c1 by Evan Brown <ezb@google.com>:

Rollback btree_iterator refactoring.

PiperOrigin-RevId: 345543900
GitOrigin-RevId: ff793052bd01e1e4fcf639f94d7c30c4855a9372
Change-Id: I719831981fd056de41939f9addfee3d85e3b49b2
parent acf3390c
...@@ -29,9 +29,9 @@ http_archive( ...@@ -29,9 +29,9 @@ http_archive(
# Google benchmark. # Google benchmark.
http_archive( http_archive(
name = "com_github_google_benchmark", name = "com_github_google_benchmark",
urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"], urls = ["https://github.com/google/benchmark/archive/bf585a2789e30585b4e3ce6baf11ef2750b54677.zip"], # 2020-11-26T11:14:03Z
strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be", strip_prefix = "benchmark-bf585a2789e30585b4e3ce6baf11ef2750b54677",
sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3", sha256 = "2a778d821997df7d8646c9c59b8edb9a573a6e04c534c01892a40aa524a7b68c",
) )
# C++ rules for Bazel. # C++ rules for Bazel.
......
...@@ -630,6 +630,45 @@ cc_test( ...@@ -630,6 +630,45 @@ cc_test(
], ],
) )
cc_binary(
name = "raw_hash_set_benchmark",
testonly = 1,
srcs = ["internal/raw_hash_set_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":hash_function_defaults",
":raw_hash_set",
"//absl/base:raw_logging_internal",
"//absl/strings:str_format",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_binary(
name = "raw_hash_set_probe_benchmark",
testonly = 1,
srcs = ["internal/raw_hash_set_probe_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = select({
"//conditions:default": [],
}) + ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":flat_hash_map",
":hash_function_defaults",
":hashtable_debug",
":raw_hash_set",
"//absl/random",
"//absl/random:distributions",
"//absl/strings",
"//absl/strings:str_format",
],
)
cc_test( cc_test(
name = "raw_hash_set_allocator_test", name = "raw_hash_set_allocator_test",
size = "small", size = "small",
...@@ -677,6 +716,22 @@ cc_test( ...@@ -677,6 +716,22 @@ cc_test(
], ],
) )
cc_binary(
name = "layout_benchmark",
testonly = 1,
srcs = ["internal/layout_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":layout",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_library( cc_library(
name = "tracked", name = "tracked",
testonly = 1, testonly = 1,
......
...@@ -298,9 +298,10 @@ class Storage { ...@@ -298,9 +298,10 @@ class Storage {
// Storage Constructors and Destructor // Storage Constructors and Destructor
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
Storage() : metadata_() {} Storage() : metadata_(allocator_type(), /* size and is_allocated */ 0) {}
explicit Storage(const allocator_type& alloc) : metadata_(alloc, {}) {} explicit Storage(const allocator_type& alloc)
: metadata_(alloc, /* size and is_allocated */ 0) {}
~Storage() { ~Storage() {
pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData(); pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
......
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Every benchmark should have the same performance as the corresponding
// headroom benchmark.
#include "absl/base/internal/raw_logging.h"
#include "absl/container/internal/layout.h"
#include "benchmark/benchmark.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
using ::benchmark::DoNotOptimize;
using Int128 = int64_t[2];
// This benchmark provides the upper bound on performance for BM_OffsetConstant.
template <size_t Offset, class... Ts>
void BM_OffsetConstantHeadroom(benchmark::State& state) {
for (auto _ : state) {
DoNotOptimize(Offset);
}
}
template <size_t Offset, class... Ts>
void BM_OffsetConstant(benchmark::State& state) {
using L = Layout<Ts...>;
ABSL_RAW_CHECK(L::Partial(3, 5, 7).template Offset<3>() == Offset,
"Invalid offset");
for (auto _ : state) {
DoNotOptimize(L::Partial(3, 5, 7).template Offset<3>());
}
}
template <class... Ts>
size_t VariableOffset(size_t n, size_t m, size_t k);
template <>
size_t VariableOffset<int8_t, int16_t, int32_t, Int128>(size_t n, size_t m,
size_t k) {
auto Align = [](size_t n, size_t m) { return (n + m - 1) & ~(m - 1); };
return Align(Align(Align(n * 1, 2) + m * 2, 4) + k * 4, 8);
}
template <>
size_t VariableOffset<Int128, int32_t, int16_t, int8_t>(size_t n, size_t m,
size_t k) {
// No alignment is necessary.
return n * 16 + m * 4 + k * 2;
}
// This benchmark provides the upper bound on performance for BM_OffsetVariable.
template <size_t Offset, class... Ts>
void BM_OffsetVariableHeadroom(benchmark::State& state) {
size_t n = 3;
size_t m = 5;
size_t k = 7;
ABSL_RAW_CHECK(VariableOffset<Ts...>(n, m, k) == Offset, "Invalid offset");
for (auto _ : state) {
DoNotOptimize(n);
DoNotOptimize(m);
DoNotOptimize(k);
DoNotOptimize(VariableOffset<Ts...>(n, m, k));
}
}
template <size_t Offset, class... Ts>
void BM_OffsetVariable(benchmark::State& state) {
using L = Layout<Ts...>;
size_t n = 3;
size_t m = 5;
size_t k = 7;
ABSL_RAW_CHECK(L::Partial(n, m, k).template Offset<3>() == Offset,
"Inavlid offset");
for (auto _ : state) {
DoNotOptimize(n);
DoNotOptimize(m);
DoNotOptimize(k);
DoNotOptimize(L::Partial(n, m, k).template Offset<3>());
}
}
// Run all benchmarks in two modes:
//
// Layout with padding: int8_t[3], int16_t[5], int32_t[7], Int128[?].
// Layout without padding: Int128[3], int32_t[5], int16_t[7], int8_t[?].
#define OFFSET_BENCHMARK(NAME, OFFSET, T1, T2, T3, T4) \
auto& NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4 = \
NAME<OFFSET, T1, T2, T3, T4>; \
BENCHMARK(NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4)
OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 48, int8_t, int16_t, int32_t,
Int128);
OFFSET_BENCHMARK(BM_OffsetConstant, 48, int8_t, int16_t, int32_t, Int128);
OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 82, Int128, int32_t, int16_t,
int8_t);
OFFSET_BENCHMARK(BM_OffsetConstant, 82, Int128, int32_t, int16_t, int8_t);
OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 48, int8_t, int16_t, int32_t,
Int128);
OFFSET_BENCHMARK(BM_OffsetVariable, 48, int8_t, int16_t, int32_t, Int128);
OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 82, Int128, int32_t, int16_t,
int8_t);
OFFSET_BENCHMARK(BM_OffsetVariable, 82, Int128, int32_t, int16_t, int8_t);
} // namespace
} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl
...@@ -82,6 +82,24 @@ cc_test( ...@@ -82,6 +82,24 @@ cc_test(
], ],
) )
cc_binary(
name = "hash_benchmark",
testonly = 1,
srcs = ["hash_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":hash",
"//absl/base:core_headers",
"//absl/random",
"//absl/strings:cord",
"//absl/strings:cord_test_helpers",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_library( cc_library(
name = "spy_hash_state", name = "spy_hash_state",
testonly = 1, testonly = 1,
......
...@@ -58,7 +58,6 @@ using ::absl::cord_internal::kMaxFlatLength; ...@@ -58,7 +58,6 @@ using ::absl::cord_internal::kMaxFlatLength;
using ::absl::cord_internal::CONCAT; using ::absl::cord_internal::CONCAT;
using ::absl::cord_internal::EXTERNAL; using ::absl::cord_internal::EXTERNAL;
using ::absl::cord_internal::FLAT; using ::absl::cord_internal::FLAT;
using ::absl::cord_internal::MAX_FLAT_TAG;
using ::absl::cord_internal::SUBSTRING; using ::absl::cord_internal::SUBSTRING;
namespace cord_internal { namespace cord_internal {
...@@ -93,6 +92,15 @@ inline const CordRepExternal* CordRep::external() const { ...@@ -93,6 +92,15 @@ inline const CordRepExternal* CordRep::external() const {
return static_cast<const CordRepExternal*>(this); return static_cast<const CordRepExternal*>(this);
} }
inline CordRepFlat* CordRep::flat() {
assert(tag >= FLAT);
return static_cast<CordRepFlat*>(this);
}
inline const CordRepFlat* CordRep::flat() const {
assert(tag >= FLAT);
return static_cast<const CordRepFlat*>(this);
}
} // namespace cord_internal } // namespace cord_internal
// Prefer copying blocks of at most this size, otherwise reference count. // Prefer copying blocks of at most this size, otherwise reference count.
...@@ -457,7 +465,7 @@ static inline bool PrepareAppendRegion(CordRep* root, char** region, ...@@ -457,7 +465,7 @@ static inline bool PrepareAppendRegion(CordRep* root, char** region,
} }
const size_t in_use = dst->length; const size_t in_use = dst->length;
const size_t capacity = static_cast<CordRepFlat*>(dst)->Capacity(); const size_t capacity = dst->flat()->Capacity();
if (in_use == capacity) { if (in_use == capacity) {
*region = nullptr; *region = nullptr;
*size = 0; *size = 0;
...@@ -539,7 +547,7 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size) { ...@@ -539,7 +547,7 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size) {
// will return true. // will return true.
static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) { static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) {
if (rep->tag >= FLAT) { if (rep->tag >= FLAT) {
*total_mem_usage += static_cast<const CordRepFlat*>(rep)->AllocatedSize(); *total_mem_usage += rep->flat()->AllocatedSize();
return true; return true;
} }
if (rep->tag == EXTERNAL) { if (rep->tag == EXTERNAL) {
...@@ -637,7 +645,7 @@ Cord& Cord::operator=(absl::string_view src) { ...@@ -637,7 +645,7 @@ Cord& Cord::operator=(absl::string_view src) {
return *this; return *this;
} }
if (tree != nullptr && tree->tag >= FLAT && if (tree != nullptr && tree->tag >= FLAT &&
static_cast<CordRepFlat*>(tree)->Capacity() >= length && tree->flat()->Capacity() >= length &&
tree->refcount.IsOne()) { tree->refcount.IsOne()) {
// Copy in place if the existing FLAT node is reusable. // Copy in place if the existing FLAT node is reusable.
memmove(tree->data, data, length); memmove(tree->data, data, length);
...@@ -694,7 +702,7 @@ void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) { ...@@ -694,7 +702,7 @@ void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) {
const size_t size2 = inline_length + src_size / 10; const size_t size2 = inline_length + src_size / 10;
root = CordRepFlat::New(std::max<size_t>(size1, size2)); root = CordRepFlat::New(std::max<size_t>(size1, size2));
appended = std::min( appended = std::min(
src_size, static_cast<CordRepFlat*>(root)->Capacity() - inline_length); src_size, root->flat()->Capacity() - inline_length);
memcpy(root->data, data_.as_chars, inline_length); memcpy(root->data, data_.as_chars, inline_length);
memcpy(root->data + inline_length, src_data, appended); memcpy(root->data + inline_length, src_data, appended);
root->length = inline_length + appended; root->length = inline_length + appended;
...@@ -1785,7 +1793,7 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os) { ...@@ -1785,7 +1793,7 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os) {
*os << absl::CEscape(std::string(rep->external()->base, rep->length)); *os << absl::CEscape(std::string(rep->external()->base, rep->length));
*os << "]\n"; *os << "]\n";
} else { } else {
*os << "FLAT cap=" << static_cast<CordRepFlat*>(rep)->Capacity() *os << "FLAT cap=" << rep->flat()->Capacity()
<< " ["; << " [";
if (include_data) if (include_data)
*os << absl::CEscape(std::string(rep->data, rep->length)); *os << absl::CEscape(std::string(rep->data, rep->length));
...@@ -1835,7 +1843,7 @@ static bool VerifyNode(CordRep* root, CordRep* start_node, ...@@ -1835,7 +1843,7 @@ static bool VerifyNode(CordRep* root, CordRep* start_node,
} }
} else if (node->tag >= FLAT) { } else if (node->tag >= FLAT) {
ABSL_INTERNAL_CHECK( ABSL_INTERNAL_CHECK(
node->length <= static_cast<CordRepFlat*>(node)->Capacity(), node->length <= node->flat()->Capacity(),
ReportError(root, node)); ReportError(root, node));
} else if (node->tag == EXTERNAL) { } else if (node->tag == EXTERNAL) {
ABSL_INTERNAL_CHECK(node->external()->base != nullptr, ABSL_INTERNAL_CHECK(node->external()->base != nullptr,
......
...@@ -149,6 +149,8 @@ struct CordRep { ...@@ -149,6 +149,8 @@ struct CordRep {
inline const CordRepSubstring* substring() const; inline const CordRepSubstring* substring() const;
inline CordRepExternal* external(); inline CordRepExternal* external();
inline const CordRepExternal* external() const; inline const CordRepExternal* external() const;
inline CordRepFlat* flat();
inline const CordRepFlat* flat() const;
}; };
struct CordRepConcat : public CordRep { struct CordRepConcat : public CordRep {
......
...@@ -43,7 +43,7 @@ static constexpr size_t kMaxFlatSize = 4096; ...@@ -43,7 +43,7 @@ static constexpr size_t kMaxFlatSize = 4096;
static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead; static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead; static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
static constexpr size_t AllocatedSizeToTagUnchecked(size_t size) { constexpr size_t AllocatedSizeToTagUnchecked(size_t size) {
return (size <= 1024) ? size / 8 : 128 + size / 32 - 1024 / 32; return (size <= 1024) ? size / 8 : 128 + size / 32 - 1024 / 32;
} }
...@@ -51,12 +51,12 @@ static_assert(kMinFlatSize / 8 >= FLAT, ""); ...@@ -51,12 +51,12 @@ static_assert(kMinFlatSize / 8 >= FLAT, "");
static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, ""); static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, "");
// Helper functions for rounded div, and rounding to exact sizes. // Helper functions for rounded div, and rounding to exact sizes.
static size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; } constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
static size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; } constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
// Returns the size to the nearest equal or larger value that can be // Returns the size to the nearest equal or larger value that can be
// expressed exactly as a tag value. // expressed exactly as a tag value.
static size_t RoundUpForTag(size_t size) { inline size_t RoundUpForTag(size_t size) {
return RoundUp(size, (size <= 1024) ? 8 : 32); return RoundUp(size, (size <= 1024) ? 8 : 32);
} }
...@@ -64,19 +64,19 @@ static size_t RoundUpForTag(size_t size) { ...@@ -64,19 +64,19 @@ static size_t RoundUpForTag(size_t size) {
// does not exactly match a 'tag expressible' size value. The result is // does not exactly match a 'tag expressible' size value. The result is
// undefined if the size exceeds the maximum size that can be encoded in // undefined if the size exceeds the maximum size that can be encoded in
// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>). // a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
static uint8_t AllocatedSizeToTag(size_t size) { inline uint8_t AllocatedSizeToTag(size_t size) {
const size_t tag = AllocatedSizeToTagUnchecked(size); const size_t tag = AllocatedSizeToTagUnchecked(size);
assert(tag <= MAX_FLAT_TAG); assert(tag <= MAX_FLAT_TAG);
return tag; return tag;
} }
// Converts the provided tag to the corresponding allocated size // Converts the provided tag to the corresponding allocated size
static constexpr size_t TagToAllocatedSize(uint8_t tag) { constexpr size_t TagToAllocatedSize(uint8_t tag) {
return (tag <= 128) ? (tag * 8) : (1024 + (tag - 128) * 32); return (tag <= 128) ? (tag * 8) : (1024 + (tag - 128) * 32);
} }
// Converts the provided tag to the corresponding available data length // Converts the provided tag to the corresponding available data length
static constexpr size_t TagToLength(uint8_t tag) { constexpr size_t TagToLength(uint8_t tag) {
return TagToAllocatedSize(tag) - kFlatOverhead; return TagToAllocatedSize(tag) - kFlatOverhead;
} }
......
...@@ -48,6 +48,10 @@ inline bool StrContains(absl::string_view haystack, ...@@ -48,6 +48,10 @@ inline bool StrContains(absl::string_view haystack,
return haystack.find(needle, 0) != haystack.npos; return haystack.find(needle, 0) != haystack.npos;
} }
inline bool StrContains(absl::string_view haystack, char needle) noexcept {
return haystack.find(needle) != haystack.npos;
}
// StartsWith() // StartsWith()
// //
// Returns whether a given string `text` begins with `prefix`. // Returns whether a given string `text` begins with `prefix`.
......
...@@ -66,6 +66,23 @@ TEST(MatchTest, Contains) { ...@@ -66,6 +66,23 @@ TEST(MatchTest, Contains) {
EXPECT_FALSE(absl::StrContains("", "a")); EXPECT_FALSE(absl::StrContains("", "a"));
} }
TEST(MatchTest, ContainsChar) {
absl::string_view a("abcdefg");
absl::string_view b("abcd");
EXPECT_TRUE(absl::StrContains(a, 'a'));
EXPECT_TRUE(absl::StrContains(a, 'b'));
EXPECT_TRUE(absl::StrContains(a, 'e'));
EXPECT_FALSE(absl::StrContains(a, 'h'));
EXPECT_TRUE(absl::StrContains(b, 'a'));
EXPECT_TRUE(absl::StrContains(b, 'b'));
EXPECT_FALSE(absl::StrContains(b, 'e'));
EXPECT_FALSE(absl::StrContains(b, 'h'));
EXPECT_FALSE(absl::StrContains("", 'a'));
EXPECT_FALSE(absl::StrContains("", 'a'));
}
TEST(MatchTest, ContainsNull) { TEST(MatchTest, ContainsNull) {
const std::string s = "foo"; const std::string s = "foo";
const char* cs = "foo"; const char* cs = "foo";
......
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