Roll abseil_revision 27c30ec671..8f11724067.
Change Log:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+log/27c30ec671..8f11724067
Full diff:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+/27c30ec671..8f11724067
Manual change:
Abseil is migrating to ABSL_ prefixed thread annotations, in order to
do so, a backwards compatible absl/base/internal/thread_annotations.h
has been created (with unprefixed thread annotations). This file is
excluded from this CL because unprefixed thread annotations are
problematic to Chromium and they were in fact prefixed by [1] during
every roll.
[1] - https://cs.chromium.org/chromium/src/third_party/abseil-cpp/rename_annotations.sh?l=130-165&rcl=0ec2bec15811f730af0ad00cb3a30b9bc86d821d
Bug: None
Change-Id: Idc60ee93f6354f70e1d24114836d8b4ce8ea9179
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1663135
Commit-Queue: Mirko Bonadei <mbonadei@chromium.org>
Reviewed-by: Nico Weber <thakis@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#670106}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 95e1aa6a4816ef6d55fbce07170f3ff044a3de43
diff --git a/CMake/install_test_project/CMakeLists.txt b/CMake/install_test_project/CMakeLists.txt
index b8e27dd..06b797e 100644
--- a/CMake/install_test_project/CMakeLists.txt
+++ b/CMake/install_test_project/CMakeLists.txt
@@ -16,7 +16,7 @@
# A simple CMakeLists.txt for testing cmake installation
cmake_minimum_required(VERSION 3.5)
-project(absl_cmake_testing)
+project(absl_cmake_testing CXX)
set(CMAKE_CXX_STANDARD 11)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e7587f7..86f5634 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,7 +30,7 @@
# Project version variables are the empty std::string if version is unspecified
cmake_policy(SET CMP0048 NEW)
-project(absl)
+project(absl CXX)
# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp))
# in the source tree of a project that uses it, install rules are disabled.
diff --git a/README.chromium b/README.chromium
index 2edc12f..c37fd3b 100644
--- a/README.chromium
+++ b/README.chromium
@@ -4,7 +4,7 @@
License: Apache 2.0
License File: LICENSE
Version: 0
-Revision: 27c30ec671cb7b5ba84c4e79feff7fd0b0ac6338
+Revision: 8f11724067248acc330b4d1f12f0c76d03f2cfb1
Security Critical: yes
Description:
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index c6f0e4d..5b7b295 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -69,6 +69,9 @@
cc_library(
name = "core_headers",
+ srcs = [
+ "internal/thread_annotations.h",
+ ],
hdrs = [
"attributes.h",
"const_init.h",
@@ -385,7 +388,6 @@
srcs = ["internal/endian_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
- ":base",
":config",
":endian",
"@com_google_googletest//:gtest_main",
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index b9f35bc..34bfba2 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -67,6 +67,7 @@
"optimization.h"
"port.h"
"thread_annotations.h"
+ "internal/thread_annotations.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
diff --git a/absl/base/config.h b/absl/base/config.h
index 2a14fe7..f12f84f 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -181,6 +181,13 @@
#endif
#endif // defined(__ANDROID__) && defined(__clang__)
+// Emscripten doesn't yet support `thread_local` or `__thread`.
+// https://github.com/emscripten-core/emscripten/issues/3502
+#if defined(__EMSCRIPTEN__)
+#undef ABSL_HAVE_TLS
+#undef ABSL_HAVE_THREAD_LOCAL
+#endif // defined(__EMSCRIPTEN__)
+
// ABSL_HAVE_INTRINSIC_INT128
//
// Checks whether the __int128 compiler extension for a 128-bit integral type is
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h
index 341f7c2..9321c3f 100644
--- a/absl/base/thread_annotations.h
+++ b/absl/base/thread_annotations.h
@@ -35,9 +35,9 @@
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
#if defined(__clang__)
-#define ABSL_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
#else
-#define ABSL_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op
#endif
// ABSL_GUARDED_BY()
@@ -57,7 +57,8 @@
// int p1_ ABSL_GUARDED_BY(mu_);
// ...
// };
-#define ABSL_GUARDED_BY(x) ABSL_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+#define ABSL_GUARDED_BY(x) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x))
// ABSL_PT_GUARDED_BY()
//
@@ -79,7 +80,8 @@
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
// // guarded by `mu2_`:
// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
-#define ABSL_PT_GUARDED_BY(x) ABSL_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+#define ABSL_PT_GUARDED_BY(x) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x))
// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
//
@@ -97,10 +99,10 @@
// Mutex m1_;
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
#define ABSL_ACQUIRED_AFTER(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__))
#define ABSL_ACQUIRED_BEFORE(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__))
// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
//
@@ -125,11 +127,12 @@
//
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
-#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
+ exclusive_locks_required(__VA_ARGS__))
#define ABSL_SHARED_LOCKS_REQUIRED(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__))
// ABSL_LOCKS_EXCLUDED()
//
@@ -137,7 +140,7 @@
// cannot be held when calling this function (as Abseil's `Mutex` locks are
// non-reentrant).
#define ABSL_LOCKS_EXCLUDED(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__))
// ABSL_LOCK_RETURNED()
//
@@ -145,13 +148,12 @@
// a public getter method that returns a pointer to a private mutex should
// be annotated with ABSL_LOCK_RETURNED.
#define ABSL_LOCK_RETURNED(x) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x))
// ABSL_LOCKABLE
//
// Documents if a class/type is a lockable type (such as the `Mutex` class).
-#define ABSL_LOCKABLE \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+#define ABSL_LOCKABLE ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable)
// ABSL_SCOPED_LOCKABLE
//
@@ -161,28 +163,29 @@
// arguments; the analysis will assume that the destructor unlocks whatever the
// constructor locked.
#define ABSL_SCOPED_LOCKABLE \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable)
// ABSL_EXCLUSIVE_LOCK_FUNCTION()
//
// Documents functions that acquire a lock in the body of a function, and do
// not release it.
-#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
+ exclusive_lock_function(__VA_ARGS__))
// ABSL_SHARED_LOCK_FUNCTION()
//
// Documents functions that acquire a shared (reader) lock in the body of a
// function, and do not release it.
#define ABSL_SHARED_LOCK_FUNCTION(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__))
// ABSL_UNLOCK_FUNCTION()
//
// Documents functions that expect a lock to be held on entry to the function,
// and release it in the body of the function.
#define ABSL_UNLOCK_FUNCTION(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__))
// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
//
@@ -193,20 +196,22 @@
// argument specifies the mutex that is locked on success. If unspecified, this
// mutex is assumed to be `this`.
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
+ exclusive_trylock_function(__VA_ARGS__))
-#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
+ shared_trylock_function(__VA_ARGS__))
// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
//
// Documents functions that dynamically check to see if a lock is held, and fail
// if it is not held.
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__))
#define ABSL_ASSERT_SHARED_LOCK(...) \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__))
// ABSL_NO_THREAD_SAFETY_ANALYSIS
//
@@ -214,7 +219,7 @@
// This annotation is used to mark functions that are known to be correct, but
// the locking behavior is more complicated than the analyzer can handle.
#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
- ABSL_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis)
//------------------------------------------------------------------------------
// Tool-Supplied Annotations
@@ -230,28 +235,29 @@
// The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED.
#define ABSL_TS_FIXME(x) ""
-// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
-// a particular function. However, this attribute is used to mark functions
+// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body
+// of a particular function. However, this attribute is used to mark functions
// that are incorrect and need to be fixed. It is used by automated tools to
// avoid breaking the build when the analysis is updated.
// Code owners are expected to eventually fix the routine.
-#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS
-// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a ABSL_GUARDED_BY
-// annotation that needs to be fixed, because it is producing thread safety
-// warning. It disables the ABSL_GUARDED_BY.
+// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a
+// ABSL_GUARDED_BY annotation that needs to be fixed, because it is producing
+// thread safety warning. It disables the ABSL_GUARDED_BY.
#define ABSL_GUARDED_BY_FIXME(x)
// Disables warnings for a single read operation. This can be used to avoid
// warnings when it is known that the read is not actually involved in a race,
// but the compiler cannot confirm that.
-#define ABSL_TS_UNCHECKED_READ(x) thread_safety_analysis::absl_ts_unchecked_read(x)
+#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::absl_ts_unchecked_read(x)
-
-namespace thread_safety_analysis {
+namespace absl {
+namespace base_internal {
// Takes a reference to a guarded data member, and returns an unguarded
// reference.
+// Do not used this function directly, use ABSL_TS_UNCHECKED_READ instead.
template <typename T>
inline const T& absl_ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
return v;
@@ -262,6 +268,7 @@
return v;
}
-} // namespace thread_safety_analysis
+} // namespace base_internal
+} // namespace absl
#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 99a7248..331030a 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -124,6 +124,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":compressed_tuple",
+ "//absl/memory",
"//absl/meta:type_traits",
],
)
diff --git a/absl/container/BUILD.gn b/absl/container/BUILD.gn
index 3466fda..5ae19c4 100644
--- a/absl/container/BUILD.gn
+++ b/absl/container/BUILD.gn
@@ -63,6 +63,7 @@
deps = [
":compressed_tuple",
"../meta:type_traits",
+ "../memory",
]
}
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 526e37a..c75b0a2 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -124,6 +124,7 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::compressed_tuple
+ absl::memory
absl::type_traits
PUBLIC
)
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 564c953..046182d 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -100,9 +100,8 @@
// InlinedVector Constructors and Destructor
// ---------------------------------------------------------------------------
- // Creates an empty inlined vector with a default initialized allocator.
- InlinedVector() noexcept(noexcept(allocator_type()))
- : storage_(allocator_type()) {}
+ // Creates an empty inlined vector with a value-initialized allocator.
+ InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
// Creates an empty inlined vector with a specified allocator.
explicit InlinedVector(const allocator_type& alloc) noexcept
@@ -112,22 +111,40 @@
explicit InlinedVector(size_type n,
const allocator_type& alloc = allocator_type())
: storage_(alloc) {
- InitAssign(n);
+ if (n > static_cast<size_type>(N)) {
+ pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), n);
+ storage_.SetAllocatedData(new_data, n);
+ UninitializedFill(storage_.GetAllocatedData(),
+ storage_.GetAllocatedData() + n);
+ storage_.SetAllocatedSize(n);
+ } else {
+ UninitializedFill(storage_.GetInlinedData(),
+ storage_.GetInlinedData() + n);
+ storage_.SetInlinedSize(n);
+ }
}
// Creates an inlined vector with `n` copies of `v`.
InlinedVector(size_type n, const_reference v,
const allocator_type& alloc = allocator_type())
: storage_(alloc) {
- InitAssign(n, v);
+ if (n > static_cast<size_type>(N)) {
+ pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), n);
+ storage_.SetAllocatedData(new_data, n);
+ UninitializedFill(storage_.GetAllocatedData(),
+ storage_.GetAllocatedData() + n, v);
+ storage_.SetAllocatedSize(n);
+ } else {
+ UninitializedFill(storage_.GetInlinedData(),
+ storage_.GetInlinedData() + n, v);
+ storage_.SetInlinedSize(n);
+ }
}
// Creates an inlined vector of copies of the values in `list`.
InlinedVector(std::initializer_list<value_type> list,
const allocator_type& alloc = allocator_type())
- : storage_(alloc) {
- AppendForwardRange(list.begin(), list.end());
- }
+ : InlinedVector(list.begin(), list.end(), alloc) {}
// Creates an inlined vector with elements constructed from the provided
// forward iterator range [`first`, `last`).
@@ -140,7 +157,15 @@
InlinedVector(ForwardIterator first, ForwardIterator last,
const allocator_type& alloc = allocator_type())
: storage_(alloc) {
- AppendForwardRange(first, last);
+ auto length = std::distance(first, last);
+ reserve(size() + length);
+ if (storage_.GetIsAllocated()) {
+ UninitializedCopy(first, last, storage_.GetAllocatedData() + size());
+ storage_.SetAllocatedSize(size() + length);
+ } else {
+ UninitializedCopy(first, last, storage_.GetInlinedData() + size());
+ storage_.SetInlinedSize(size() + length);
+ }
}
// Creates an inlined vector with elements constructed from the provided input
@@ -193,8 +218,8 @@
if (other.storage_.GetIsAllocated()) {
// We can just steal the underlying buffer from the source.
// That leaves the source empty, so we clear its size.
- storage_.SetAllocatedData(other.storage_.GetAllocatedData());
- storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity());
+ storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
+ other.storage_.GetAllocatedCapacity());
storage_.SetAllocatedSize(other.size());
other.storage_.SetInlinedSize(0);
} else {
@@ -227,8 +252,8 @@
if (*storage_.GetAllocPtr() == *other.storage_.GetAllocPtr()) {
// We can just steal the allocation from the source.
storage_.SetAllocatedSize(other.size());
- storage_.SetAllocatedData(other.storage_.GetAllocatedData());
- storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity());
+ storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
+ other.storage_.GetAllocatedCapacity());
other.storage_.SetInlinedSize(0);
} else {
// We need to use our own allocator
@@ -248,7 +273,7 @@
}
}
- ~InlinedVector() { clear(); }
+ ~InlinedVector() {}
// ---------------------------------------------------------------------------
// InlinedVector Member Accessors
@@ -473,8 +498,8 @@
if (other.storage_.GetIsAllocated()) {
clear();
storage_.SetAllocatedSize(other.size());
- storage_.SetAllocatedData(other.storage_.GetAllocatedData());
- storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity());
+ storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
+ other.storage_.GetAllocatedCapacity());
other.storage_.SetInlinedSize(0);
} else {
if (storage_.GetIsAllocated()) clear();
@@ -793,16 +818,8 @@
// Destroys all elements in the inlined vector, sets the size of `0` and
// deallocates the heap allocation if the inlined vector was allocated.
void clear() noexcept {
- const bool is_allocated = storage_.GetIsAllocated();
- pointer the_data =
- is_allocated ? storage_.GetAllocatedData() : storage_.GetInlinedData();
- inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), the_data,
- storage_.GetSize());
+ storage_.DestroyAndDeallocate();
storage_.SetInlinedSize(0);
- if (is_allocated) {
- AllocatorTraits::deallocate(*storage_.GetAllocPtr(), the_data,
- storage_.GetAllocatedCapacity());
- }
}
// `InlinedVector::reserve()`
@@ -883,14 +900,13 @@
Destroy(storage_.GetInlinedData(), storage_.GetInlinedData() + size());
}
- storage_.SetAllocatedData(new_data);
- storage_.SetAllocatedCapacity(new_capacity);
+ storage_.SetAllocatedData(new_data, new_capacity);
storage_.SetAllocatedSize(new_size);
}
template <typename... Args>
reference Construct(pointer p, Args&&... args) {
- std::allocator_traits<allocator_type>::construct(
+ absl::allocator_traits<allocator_type>::construct(
*storage_.GetAllocPtr(), p, std::forward<Args>(args)...);
return *p;
}
@@ -908,8 +924,8 @@
// Destroy [`from`, `to`) in place.
void Destroy(pointer from, pointer to) {
for (pointer cur = from; cur != to; ++cur) {
- std::allocator_traits<allocator_type>::destroy(*storage_.GetAllocPtr(),
- cur);
+ absl::allocator_traits<allocator_type>::destroy(*storage_.GetAllocPtr(),
+ cur);
}
#if !defined(NDEBUG)
// Overwrite unused memory with `0xab` so we can catch uninitialized usage.
@@ -1032,53 +1048,6 @@
return new_element;
}
- void InitAssign(size_type n) {
- if (n > static_cast<size_type>(N)) {
- pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), n);
- storage_.SetAllocatedData(new_data);
- storage_.SetAllocatedCapacity(n);
- UninitializedFill(storage_.GetAllocatedData(),
- storage_.GetAllocatedData() + n);
- storage_.SetAllocatedSize(n);
- } else {
- UninitializedFill(storage_.GetInlinedData(),
- storage_.GetInlinedData() + n);
- storage_.SetInlinedSize(n);
- }
- }
-
- void InitAssign(size_type n, const_reference v) {
- if (n > static_cast<size_type>(N)) {
- pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), n);
- storage_.SetAllocatedData(new_data);
- storage_.SetAllocatedCapacity(n);
- UninitializedFill(storage_.GetAllocatedData(),
- storage_.GetAllocatedData() + n, v);
- storage_.SetAllocatedSize(n);
- } else {
- UninitializedFill(storage_.GetInlinedData(),
- storage_.GetInlinedData() + n, v);
- storage_.SetInlinedSize(n);
- }
- }
-
- template <typename ForwardIt>
- void AppendForwardRange(ForwardIt first, ForwardIt last) {
- static_assert(absl::inlined_vector_internal::IsAtLeastForwardIterator<
- ForwardIt>::value,
- "");
-
- auto length = std::distance(first, last);
- reserve(size() + length);
- if (storage_.GetIsAllocated()) {
- UninitializedCopy(first, last, storage_.GetAllocatedData() + size());
- storage_.SetAllocatedSize(size() + length);
- } else {
- UninitializedCopy(first, last, storage_.GetInlinedData() + size());
- storage_.SetInlinedSize(size() + length);
- }
- }
-
iterator InsertWithCount(const_iterator position, size_type n,
const_reference v) {
assert(position >= begin() && position <= end());
@@ -1191,8 +1160,7 @@
a->Destroy(a->storage_.GetInlinedData(),
a->storage_.GetInlinedData() + a_size);
- a->storage_.SetAllocatedData(b_data);
- a->storage_.SetAllocatedCapacity(b_capacity);
+ a->storage_.SetAllocatedData(b_data, b_capacity);
if (*a->storage_.GetAllocPtr() != *b->storage_.GetAllocPtr()) {
swap(*a->storage_.GetAllocPtr(), *b->storage_.GetAllocPtr());
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc
index d906997..a8368d4 100644
--- a/absl/container/inlined_vector_benchmark.cc
+++ b/absl/container/inlined_vector_benchmark.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <array>
#include <string>
#include <vector>
@@ -373,71 +374,165 @@
}
BENCHMARK(BM_StdVectorEmpty);
-constexpr size_t kInlineElements = 4;
-constexpr size_t kSmallSize = kInlineElements / 2;
-constexpr size_t kLargeSize = kInlineElements * 2;
+constexpr size_t kInlinedCapacity = 4;
+constexpr size_t kLargeSize = kInlinedCapacity * 2;
+constexpr size_t kSmallSize = kInlinedCapacity / 2;
constexpr size_t kBatchSize = 100;
+#define ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_FunctionTemplate, T) \
+ BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kLargeSize); \
+ BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kSmallSize)
+
+template <typename T>
+using InlVec = absl::InlinedVector<T, kInlinedCapacity>;
+
struct TrivialType {
size_t val;
};
-using TrivialVec = absl::InlinedVector<TrivialType, kInlineElements>;
-
class NontrivialType {
public:
- ABSL_ATTRIBUTE_NOINLINE NontrivialType() : val_() {}
+ ABSL_ATTRIBUTE_NOINLINE NontrivialType() : val_() {
+ benchmark::DoNotOptimize(*this);
+ }
ABSL_ATTRIBUTE_NOINLINE NontrivialType(const NontrivialType& other)
- : val_(other.val_) {}
+ : val_(other.val_) {
+ benchmark::DoNotOptimize(*this);
+ }
ABSL_ATTRIBUTE_NOINLINE NontrivialType& operator=(
const NontrivialType& other) {
val_ = other.val_;
+ benchmark::DoNotOptimize(*this);
return *this;
}
- ABSL_ATTRIBUTE_NOINLINE ~NontrivialType() noexcept {}
+ ABSL_ATTRIBUTE_NOINLINE ~NontrivialType() noexcept {
+ benchmark::DoNotOptimize(*this);
+ }
private:
size_t val_;
};
-using NontrivialVec = absl::InlinedVector<NontrivialType, kInlineElements>;
-
-template <typename VecT, typename PrepareVec, typename TestVec>
-void BatchedBenchmark(benchmark::State& state, PrepareVec prepare_vec,
- TestVec test_vec) {
- VecT vectors[kBatchSize];
+template <typename T, typename PrepareVecFn, typename TestVecFn>
+void BatchedBenchmark(benchmark::State& state, PrepareVecFn prepare_vec,
+ TestVecFn test_vec) {
+ std::array<InlVec<T>, kBatchSize> vector_batch{};
while (state.KeepRunningBatch(kBatchSize)) {
// Prepare batch
state.PauseTiming();
- for (auto& vec : vectors) {
- prepare_vec(&vec);
+ for (size_t i = 0; i < kBatchSize; ++i) {
+ prepare_vec(vector_batch.data() + i, i);
}
- benchmark::DoNotOptimize(vectors);
+ benchmark::DoNotOptimize(vector_batch);
state.ResumeTiming();
// Test batch
- for (auto& vec : vectors) {
- test_vec(&vec);
+ for (size_t i = 0; i < kBatchSize; ++i) {
+ test_vec(vector_batch.data() + i, i);
}
}
}
-template <typename VecT, size_t FromSize>
-void BM_Clear(benchmark::State& state) {
- BatchedBenchmark<VecT>(
+template <typename T, size_t ToSize>
+void BM_ConstructFromSize(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ auto size = ToSize;
+ BatchedBenchmark<T>(
state,
- /* prepare_vec = */ [](VecT* vec) { vec->resize(FromSize); },
- /* test_vec = */ [](VecT* vec) { vec->clear(); });
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+ /* test_vec = */
+ [&](void* ptr, size_t) {
+ benchmark::DoNotOptimize(size);
+ ::new (ptr) VecT(size);
+ });
}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSize, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSize, NontrivialType);
-BENCHMARK_TEMPLATE(BM_Clear, TrivialVec, kSmallSize);
-BENCHMARK_TEMPLATE(BM_Clear, TrivialVec, kLargeSize);
+template <typename T, size_t ToSize>
+void BM_ConstructFromSizeRef(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ auto size = ToSize;
+ auto ref = T();
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+ /* test_vec = */
+ [&](void* ptr, size_t) {
+ benchmark::DoNotOptimize(size);
+ benchmark::DoNotOptimize(ref);
+ ::new (ptr) VecT(size, ref);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSizeRef, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSizeRef, NontrivialType);
-BENCHMARK_TEMPLATE(BM_Clear, NontrivialVec, kSmallSize);
-BENCHMARK_TEMPLATE(BM_Clear, NontrivialVec, kLargeSize);
+template <typename T, size_t ToSize>
+void BM_ConstructFromRange(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ std::array<T, ToSize> arr{};
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+ /* test_vec = */
+ [&](void* ptr, size_t) {
+ benchmark::DoNotOptimize(arr);
+ ::new (ptr) VecT(arr.begin(), arr.end());
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromRange, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromRange, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromCopy(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ VecT other_vec(ToSize);
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+ /* test_vec = */
+ [&](void* ptr, size_t) {
+ benchmark::DoNotOptimize(other_vec);
+ ::new (ptr) VecT(other_vec);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromCopy, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromCopy, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromMove(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ std::array<VecT, kBatchSize> vector_batch{};
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [&](InlVec<T>* vec, size_t i) {
+ vector_batch[i].clear();
+ vector_batch[i].resize(ToSize);
+ vec->~VecT();
+ },
+ /* test_vec = */
+ [&](void* ptr, size_t i) {
+ benchmark::DoNotOptimize(vector_batch[i]);
+ ::new (ptr) VecT(std::move(vector_batch[i]));
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType);
+
+template <typename T, size_t FromSize>
+void BM_Clear(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); },
+ /* test_vec = */ [](InlVec<T>* vec, size_t) { vec->clear(); });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_Clear, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_Clear, NontrivialType);
} // namespace
diff --git a/absl/container/inlined_vector_exception_safety_test.cc b/absl/container/inlined_vector_exception_safety_test.cc
index 0af048b..1aae0b0 100644
--- a/absl/container/inlined_vector_exception_safety_test.cc
+++ b/absl/container/inlined_vector_exception_safety_test.cc
@@ -20,36 +20,85 @@
namespace {
-constexpr size_t kInlined = 4;
-constexpr size_t kSmallSize = kInlined / 2;
-constexpr size_t kLargeSize = kInlined * 2;
+constexpr size_t kInlinedCapacity = 4;
+constexpr size_t kLargeSize = kInlinedCapacity * 2;
+constexpr size_t kSmallSize = kInlinedCapacity / 2;
using Thrower = testing::ThrowingValue<>;
-using ThrowerAlloc = testing::ThrowingAllocator<Thrower>;
+using MovableThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using ThrowAlloc = testing::ThrowingAllocator<Thrower>;
-template <typename Allocator = std::allocator<Thrower>>
-using InlVec = absl::InlinedVector<Thrower, kInlined, Allocator>;
+using ThrowerVec = absl::InlinedVector<Thrower, kInlinedCapacity>;
+using MovableThrowerVec = absl::InlinedVector<MovableThrower, kInlinedCapacity>;
-TEST(InlinedVector, DefaultConstructor) {
- testing::TestThrowingCtor<InlVec<>>();
+using ThrowAllocThrowerVec =
+ absl::InlinedVector<Thrower, kInlinedCapacity, ThrowAlloc>;
+using ThrowAllocMovableThrowerVec =
+ absl::InlinedVector<MovableThrower, kInlinedCapacity, ThrowAlloc>;
- testing::TestThrowingCtor<InlVec<ThrowerAlloc>>();
+template <typename TheVecT, size_t... TheSizes>
+class TestParams {
+ public:
+ using VecT = TheVecT;
+ constexpr static size_t GetSizeAt(size_t i) { return kSizes[1 + i]; }
+
+ private:
+ constexpr static size_t kSizes[1 + sizeof...(TheSizes)] = {1, TheSizes...};
+};
+
+using NoSizeTestParams =
+ ::testing::Types<TestParams<ThrowerVec>, TestParams<MovableThrowerVec>,
+ TestParams<ThrowAllocThrowerVec>,
+ TestParams<ThrowAllocMovableThrowerVec>>;
+
+using OneSizeTestParams =
+ ::testing::Types<TestParams<ThrowerVec, kLargeSize>,
+ TestParams<ThrowerVec, kSmallSize>,
+ TestParams<MovableThrowerVec, kLargeSize>,
+ TestParams<MovableThrowerVec, kSmallSize>,
+ TestParams<ThrowAllocThrowerVec, kLargeSize>,
+ TestParams<ThrowAllocThrowerVec, kSmallSize>,
+ TestParams<ThrowAllocMovableThrowerVec, kLargeSize>,
+ TestParams<ThrowAllocMovableThrowerVec, kSmallSize>>;
+
+template <typename>
+struct NoSizeTest : ::testing::Test {};
+TYPED_TEST_SUITE(NoSizeTest, NoSizeTestParams);
+
+template <typename>
+struct OneSizeTest : ::testing::Test {};
+TYPED_TEST_SUITE(OneSizeTest, OneSizeTestParams);
+
+// Function that always returns false is correct, but refactoring is required
+// for clarity. It's needed to express that, as a contract, certain operations
+// should not throw at all. Execution of this function means an exception was
+// thrown and thus the test should fail.
+// TODO(johnsoncj): Add `testing::NoThrowGuarantee` to the framework
+template <typename VecT>
+bool NoThrowGuarantee(VecT* /* vec */) {
+ return false;
}
-TEST(InlinedVector, AllocConstructor) {
- auto alloc = std::allocator<Thrower>();
- testing::TestThrowingCtor<InlVec<>>(alloc);
+TYPED_TEST(NoSizeTest, DefaultConstructor) {
+ using VecT = typename TypeParam::VecT;
+ using allocator_type = typename VecT::allocator_type;
- auto throw_alloc = ThrowerAlloc();
- testing::TestThrowingCtor<InlVec<ThrowerAlloc>>(throw_alloc);
+ testing::TestThrowingCtor<VecT>();
+
+ testing::TestThrowingCtor<VecT>(allocator_type{});
}
-TEST(InlinedVector, Clear) {
- auto small_vec = InlVec<>(kSmallSize);
- EXPECT_TRUE(testing::TestNothrowOp([&]() { small_vec.clear(); }));
+TYPED_TEST(OneSizeTest, Clear) {
+ using VecT = typename TypeParam::VecT;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
- auto large_vec = InlVec<>(kLargeSize);
- EXPECT_TRUE(testing::TestNothrowOp([&]() { large_vec.clear(); }));
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT(size))
+ .WithContracts(NoThrowGuarantee<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ vec->clear(); //
+ }));
}
} // namespace
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
index d2435ed..7f9e8dd 100644
--- a/absl/container/internal/hashtablez_sampler_test.cc
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -199,7 +199,7 @@
SetHashtablezSampleParameter(100);
int64_t num_sampled = 0;
int64_t total = 0;
- double sample_rate;
+ double sample_rate = 0.0;
for (int i = 0; i < 1000000; ++i) {
HashtablezInfoHandle h = Sample();
++total;
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h
index a2b3d24..f4eb92e 100644
--- a/absl/container/internal/inlined_vector.h
+++ b/absl/container/internal/inlined_vector.h
@@ -22,6 +22,7 @@
#include <utility>
#include "absl/container/internal/compressed_tuple.h"
+#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
namespace absl {
@@ -35,15 +36,7 @@
template <typename AllocatorType, typename ValueType, typename SizeType>
void DestroyElements(AllocatorType* alloc_ptr, ValueType* destroy_first,
SizeType destroy_size) {
- using AllocatorTraits = std::allocator_traits<AllocatorType>;
-
- // Destroys `destroy_size` elements from `destroy_first`.
- //
- // Destroys the range
- // [`destroy_first`, `destroy_first + destroy_size`).
- //
- // NOTE: We assume destructors do not throw and thus make no attempt to roll
- // back.
+ using AllocatorTraits = absl::allocator_traits<AllocatorType>;
for (SizeType i = 0; i < destroy_size; ++i) {
AllocatorTraits::destroy(*alloc_ptr, destroy_first + i);
}
@@ -59,6 +52,16 @@
#endif // NDEBUG
}
+template <typename AllocatorType>
+struct StorageView {
+ using pointer = typename AllocatorType::pointer;
+ using size_type = typename AllocatorType::size_type;
+
+ pointer data;
+ size_type size;
+ size_type capacity;
+};
+
template <typename T, size_t N, typename A>
class Storage {
public:
@@ -75,11 +78,17 @@
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- using AllocatorTraits = std::allocator_traits<allocator_type>;
+ using AllocatorTraits = absl::allocator_traits<allocator_type>;
+
+ using StorageView = inlined_vector_internal::StorageView<allocator_type>;
+
+ Storage() : metadata_() {}
explicit Storage(const allocator_type& alloc)
: metadata_(alloc, /* empty and inlined */ 0) {}
+ ~Storage() { DestroyAndDeallocate(); }
+
size_type GetSize() const { return GetSizeAndIsAllocated() >> 1; }
bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; }
@@ -104,6 +113,13 @@
return data_.allocated.allocated_capacity;
}
+ StorageView MakeStorageView() {
+ return GetIsAllocated() ? StorageView{GetAllocatedData(), GetSize(),
+ GetAllocatedCapacity()}
+ : StorageView{GetInlinedData(), GetSize(),
+ static_cast<size_type>(N)};
+ }
+
allocator_type* GetAllocPtr() {
return std::addressof(metadata_.template get<0>());
}
@@ -120,9 +136,8 @@
void AddSize(size_type count) { GetSizeAndIsAllocated() += count << 1; }
- void SetAllocatedData(pointer data) { data_.allocated.allocated_data = data; }
-
- void SetAllocatedCapacity(size_type capacity) {
+ void SetAllocatedData(pointer data, size_type capacity) {
+ data_.allocated.allocated_data = data;
data_.allocated.allocated_capacity = capacity;
}
@@ -136,6 +151,8 @@
swap(data_.allocated, other->data_.allocated);
}
+ void DestroyAndDeallocate();
+
private:
size_type& GetSizeAndIsAllocated() { return metadata_.template get<1>(); }
@@ -166,6 +183,20 @@
Data data_;
};
+template <typename T, size_t N, typename A>
+void Storage<T, N, A>::DestroyAndDeallocate() {
+ namespace ivi = inlined_vector_internal;
+
+ StorageView storage_view = MakeStorageView();
+
+ ivi::DestroyElements(GetAllocPtr(), storage_view.data, storage_view.size);
+
+ if (GetIsAllocated()) {
+ AllocatorTraits::deallocate(*GetAllocPtr(), storage_view.data,
+ storage_view.capacity);
+ }
+}
+
} // namespace inlined_vector_internal
} // namespace absl
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 02030bd..c4889cd 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -350,7 +350,7 @@
return BitMask<uint32_t, kWidth>(
_mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl)));
#else
- return Match(kEmpty);
+ return Match(static_cast<h2_t>(kEmpty));
#endif
}
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index e4aed5e..913cfaf 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -61,6 +61,7 @@
":demangle_internal",
"//absl/base",
"//absl/base:core_headers",
+ "//absl/base:dynamic_annotations",
"//absl/base:malloc_internal",
],
)
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index d813fed..001e272 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -50,6 +50,7 @@
absl::demangle_internal
absl::base
absl::core_headers
+ absl::dynamic_annotations
absl::malloc_internal
PUBLIC
)
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h
index 99b3758..d84200d 100644
--- a/absl/debugging/internal/elf_mem_image.h
+++ b/absl/debugging/internal/elf_mem_image.h
@@ -34,7 +34,7 @@
#define ABSL_HAVE_ELF_MEM_IMAGE 1
#endif
-#if ABSL_HAVE_ELF_MEM_IMAGE
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
#include <link.h> // for ElfW
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc
index 7ed3bd3..5a55f29 100644
--- a/absl/debugging/symbolize_win32.inc
+++ b/absl/debugging/symbolize_win32.inc
@@ -23,7 +23,7 @@
#include <DbgHelp.h>
#pragma warning(pop)
-#pragma comment(lib, "DbgHelp")
+#pragma comment(lib, "dbghelp.lib")
#include <algorithm>
#include <cstring>
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 6402866..9b32f46 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -56,7 +56,7 @@
// forward declared types.
// auto IsCopyConstructible(const T& v) -> decltype(T(v));
// auto HasAbslParseFlag(absl::string_view in, T* dst, std::string* err)
- // -> decltype(AbslParseFlag(in, dst, GlobalStringADLGuard(err)));
+ // -> decltype(AbslParseFlag(in, dst, err));
// auto HasAbslUnparseFlag(const T& v) -> decltype(AbslUnparseFlag(v));
};
diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h
index 669cf45..7eb75cd 100644
--- a/absl/flags/marshalling.h
+++ b/absl/flags/marshalling.h
@@ -185,18 +185,11 @@
bool AbslParseFlag(absl::string_view, std::string*, std::string*);
bool AbslParseFlag(absl::string_view, std::vector<std::string>*, std::string*);
-struct GlobalStringADLGuard {
- explicit GlobalStringADLGuard(std::string* p) : ptr(p) {}
- operator std::string*() { return ptr; } // NOLINT
- std::string* ptr;
-};
-
template <typename T>
bool InvokeParseFlag(absl::string_view input, T* dst, std::string* err) {
// Comment on next line provides a good compiler error message if T
// does not have AbslParseFlag(absl::string_view, T*, std::string*).
- return AbslParseFlag( // Is T missing AbslParseFlag?
- input, dst, GlobalStringADLGuard(err));
+ return AbslParseFlag(input, dst, err); // Is T missing AbslParseFlag?
}
// Strings and std:: containers do not have the same overload resolution
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 449e77b..bab560b 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -524,6 +524,7 @@
template <InvokeTag... Tags>
struct CustomHashType {
+ explicit CustomHashType(size_t val) : value(val) {}
size_t value;
};
@@ -590,7 +591,7 @@
EXPECT_TRUE(is_hashable<const type&>());
const size_t offset = static_cast<int>(std::min({T::value...}));
- EXPECT_EQ(SpyHash(type{7}), SpyHash(size_t{7 + offset}));
+ EXPECT_EQ(SpyHash(type(7)), SpyHash(size_t{7 + offset}));
}
void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) {
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
index 559ee0a..a99aac0 100644
--- a/absl/strings/str_cat.h
+++ b/absl/strings/str_cat.h
@@ -37,7 +37,8 @@
// 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").
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index da3208e..0b93c28 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -20,7 +20,8 @@
// 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:
//
@@ -67,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_
@@ -211,6 +213,11 @@
// 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.
//
@@ -226,7 +233,7 @@
// "%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;
// std::string s = absl::StrFormat(
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 80830b3..96c6234 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -271,7 +271,7 @@
EXPECT_EQ(errno, EBADF);
}
-#if __GLIBC__
+#ifdef __GLIBC__
TEST_F(FormatEntryPointTest, FprintfTooLarge) {
std::FILE* f = std::fopen("/dev/null", "w");
int width = 2000000000;
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
index 32dec30..233e9dc 100644
--- a/absl/strings/substitute.h
+++ b/absl/strings/substitute.h
@@ -35,10 +35,13 @@
// 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:
-// std::string s = Substitute("$1 purchased $0 $2. Thanks $1!",
+// std::string s = Substitute("$1 purchased $0 $2 for $$10. Thanks $1!",
// 5, "Bob", "Apples");
-// EXPECT_EQ("Bob purchased 5 Apples. Thanks Bob!", s);
+// EXPECT_EQ("Bob purchased 5 Apples for $10. Thanks Bob!", s);
//
// Example 2:
// std::string s = "Hi. ";
diff --git a/absl/time/civil_time.h b/absl/time/civil_time.h
index 2dfcbd2..6bb7eec 100644
--- a/absl/time/civil_time.h
+++ b/absl/time/civil_time.h
@@ -407,9 +407,9 @@
//
// absl::CivilDay d = ...
// // Gets the following Thursday if d is not already Thursday
-// absl::CivilDay thurs1 = absl::PrevWeekday(d, absl::Weekday::thursday) + 7;
+// absl::CivilDay thurs1 = absl::NextWeekday(d - 1, absl::Weekday::thursday);
// // Gets the previous Thursday if d is not already Thursday
-// absl::CivilDay thurs2 = absl::NextWeekday(d, absl::Weekday::thursday) - 7;
+// absl::CivilDay thurs2 = absl::PrevWeekday(d + 1, absl::Weekday::thursday);
//
inline CivilDay NextWeekday(CivilDay cd, Weekday wd) {
return CivilDay(time_internal::cctz::next_weekday(cd, wd));
diff --git a/absl/time/civil_time_test.cc b/absl/time/civil_time_test.cc
index b8d5713..070f0d5 100644
--- a/absl/time/civil_time_test.cc
+++ b/absl/time/civil_time_test.cc
@@ -1028,7 +1028,7 @@
TEST(CivilTime, FirstThursdayInMonth) {
const absl::CivilDay nov1(2014, 11, 1);
const absl::CivilDay thursday =
- absl::PrevWeekday(nov1, absl::Weekday::thursday) + 7;
+ absl::NextWeekday(nov1 - 1, absl::Weekday::thursday);
EXPECT_EQ("2014-11-06", absl::FormatCivilTime(thursday));
// Bonus: Date of Thanksgiving in the United States
diff --git a/absl/time/internal/cctz/include/cctz/civil_time.h b/absl/time/internal/cctz/include/cctz/civil_time.h
index f844182..aa578ee 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time.h
@@ -306,9 +306,9 @@
//
// civil_day d = ...
// // Gets the following Thursday if d is not already Thursday
-// civil_day thurs1 = prev_weekday(d, weekday::thursday) + 7;
+// civil_day thurs1 = next_weekday(d - 1, weekday::thursday);
// // Gets the previous Thursday if d is not already Thursday
-// civil_day thurs2 = next_weekday(d, weekday::thursday) - 7;
+// civil_day thurs2 = prev_weekday(d + 1, weekday::thursday);
//
using detail::next_weekday;
using detail::prev_weekday;
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc
index dc7e5a1..b1f46f1 100644
--- a/absl/time/internal/cctz/src/civil_time_test.cc
+++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -1035,7 +1035,7 @@
TEST(CivilTime, FirstThursdayInMonth) {
const civil_day nov1(2014, 11, 1);
- const civil_day thursday = prev_weekday(nov1, weekday::thursday) + 7;
+ const civil_day thursday = next_weekday(nov1 - 1, weekday::thursday);
EXPECT_EQ("2014-11-06", Format(thursday));
// Bonus: Date of Thanksgiving in the United States
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
index 81ece72..b0d159a 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -27,7 +27,7 @@
namespace {
// The prefix used for the internal names of fixed-offset zones.
-const char kFixedOffsetPrefix[] = "Fixed/UTC";
+const char kFixedZonePrefix[] = "Fixed/UTC";
const char kDigits[] = "0123456789";
@@ -55,11 +55,11 @@
return true;
}
- const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
- const char* const ep = kFixedOffsetPrefix + prefix_len;
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+ const char* const ep = kFixedZonePrefix + prefix_len;
if (name.size() != prefix_len + 9) // <prefix>+99:99:99
return false;
- if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
+ if (!std::equal(kFixedZonePrefix, ep, name.begin()))
return false;
const char* np = name.data() + prefix_len;
if (np[0] != '+' && np[0] != '-')
@@ -102,9 +102,9 @@
}
int hours = minutes / 60;
minutes %= 60;
- char buf[sizeof(kFixedOffsetPrefix) - 1 + sizeof("-24:00:00")];
- std::strcpy(buf, kFixedOffsetPrefix);
- char* ep = buf + sizeof(kFixedOffsetPrefix) - 1;
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+ char buf[prefix_len + sizeof("-24:00:00")];
+ char* ep = std::copy(kFixedZonePrefix, kFixedZonePrefix + prefix_len, buf);
*ep++ = sign;
ep = Format02d(ep, hours);
*ep++ = ':';
@@ -118,7 +118,7 @@
std::string FixedOffsetToAbbr(const seconds& offset) {
std::string abbr = FixedOffsetToName(offset);
- const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99
abbr.erase(0, prefix_len); // +99:99:99
abbr.erase(6, 1); // +99:9999
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
index 50f7de5..184bd43 100644
--- a/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -682,7 +682,6 @@
// Use of the "file:" prefix is intended for testing purposes only.
if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
-#if defined(__ANDROID__)
// See Android's libc/tzcode/bionic.cpp for additional information.
for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
"/system/usr/share/zoneinfo/tzdata"}) {
@@ -717,7 +716,7 @@
}
}
}
-#endif // __ANDROID__
+
return nullptr;
}
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index 3ab1623..6095e76 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -21,7 +21,6 @@
#include <chrono>
#include <ctime>
#include <limits>
-#include <tuple>
#include <utility>
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
@@ -33,57 +32,75 @@
namespace {
-// .first is seconds east of UTC; .second is the time-zone abbreviation.
-using OffsetAbbr = std::pair<int, const char*>;
-
-// Defines a function that can be called as follows:
-//
-// std::tm tm = ...;
-// OffsetAbbr off_abbr = get_offset_abbr(tm);
-//
#if defined(_WIN32) || defined(_WIN64)
// Uses the globals: '_timezone', '_dstbias' and '_tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + _dstbias) {
const bool is_dst = tm.tm_isdst > 0;
- const int off = _timezone + (is_dst ? _dstbias : 0);
- const char* abbr = _tzname[is_dst];
- return {off, abbr};
+ return _timezone + (is_dst ? _dstbias : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return _tzname[is_dst];
}
#elif defined(__sun)
// Uses the globals: 'timezone', 'altzone' and 'tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
const bool is_dst = tm.tm_isdst > 0;
- const int off = is_dst ? altzone : timezone;
- const char* abbr = tzname[is_dst];
- return {off, abbr};
+ return is_dst ? altzone : timezone;
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return tzname[is_dst];
}
#elif defined(__native_client__) || defined(__myriad2__) || \
defined(__EMSCRIPTEN__)
// Uses the globals: 'timezone' and 'tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) {
const bool is_dst = tm.tm_isdst > 0;
- const int off = _timezone + (is_dst ? 60 * 60 : 0);
- const char* abbr = tzname[is_dst];
- return {off, abbr};
+ return _timezone + (is_dst ? 60 * 60 : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return tzname[is_dst];
}
#else
-//
-// Returns an OffsetAbbr using std::tm fields with various spellings.
-//
-#if !defined(tm_gmtoff) && !defined(tm_zone)
-template <typename T>
-OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::tm_gmtoff) = nullptr,
- decltype(&T::tm_zone) = nullptr) {
- return {tm.tm_gmtoff, tm.tm_zone};
+// Adapt to different spellings of the struct std::tm extension fields.
+#if defined(tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.tm_gmtoff) {
+ return tm.tm_gmtoff;
}
-#endif // !defined(tm_gmtoff) && !defined(tm_zone)
-#if !defined(__tm_gmtoff) && !defined(__tm_zone)
-template <typename T>
-OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr,
- decltype(&T::__tm_zone) = nullptr) {
- return {tm.__tm_gmtoff, tm.__tm_zone};
+#elif defined(__tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) {
+ return tm.__tm_gmtoff;
}
-#endif // !defined(__tm_gmtoff) && !defined(__tm_zone)
+#else
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) {
+ return tm.tm_gmtoff;
+}
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) {
+ return tm.__tm_gmtoff;
+}
+#endif // tm_gmtoff
+#if defined(tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) {
+ return tm.tm_zone;
+}
+#elif defined(__tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
+ return tm.__tm_zone;
+}
+#else
+template <typename T>
+auto tm_zone(const T& tm) -> decltype(tm.tm_zone) {
+ return tm.tm_zone;
+}
+template <typename T>
+auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) {
+ return tm.__tm_zone;
+}
+#endif // tm_zone
#endif
inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
@@ -126,7 +143,7 @@
return false;
}
}
- *off = get_offset_abbr(tm).first;
+ *off = static_cast<int>(tm_gmtoff(tm));
return true;
}
@@ -137,7 +154,7 @@
while (lo + 1 != hi) {
const std::time_t mid = lo + (hi - lo) / 2;
if (std::tm* tmp = local_time(&mid, &tm)) {
- if (get_offset_abbr(*tmp).first == offset) {
+ if (tm_gmtoff(*tmp) == offset) {
hi = mid;
} else {
lo = mid;
@@ -147,7 +164,7 @@
// ignoring all failed conversions. Slow, but never really happens.
while (++lo != hi) {
if (std::tm* tmp = local_time(&lo, &tm)) {
- if (get_offset_abbr(*tmp).first == offset) break;
+ if (tm_gmtoff(*tmp) == offset) break;
}
}
return lo;
@@ -193,8 +210,8 @@
const year_t year = tmp->tm_year + year_t{1900};
al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- std::tie(al.offset, al.abbr) = get_offset_abbr(*tmp);
- if (!local_) al.abbr = "UTC"; // as expected by cctz
+ al.offset = static_cast<int>(tm_gmtoff(*tmp));
+ al.abbr = local_ ? tm_zone(*tmp) : "UTC"; // as expected by cctz
al.is_dst = tmp->tm_isdst > 0;
return al;
}
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc
index 1324846..42f50c5 100644
--- a/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -46,7 +46,13 @@
// A "weak" definition for cctz_extension::zone_info_source_factory.
// The user may override this with their own "strong" definition (see
// zone_info_source.h).
-#if defined(_MSC_VER)
+#if !defined(__has_attribute)
+#define __has_attribute(x) 0
+#endif
+#if __has_attribute(weak) || defined(__GNUC__)
+ZoneInfoSourceFactory zone_info_source_factory
+ __attribute__((weak)) = DefaultFactory;
+#elif defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
extern ZoneInfoSourceFactory zone_info_source_factory;
extern ZoneInfoSourceFactory default_factory;
ZoneInfoSourceFactory default_factory = DefaultFactory;
@@ -60,19 +66,11 @@
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA")
#else
#error Unsupported MSVC platform
-#endif
-#else // _MSC_VER
-#if !defined(__has_attribute)
-#define __has_attribute(x) 0
-#endif
-#if __has_attribute(weak) || defined(__GNUC__)
-ZoneInfoSourceFactory zone_info_source_factory
- __attribute__((weak)) = DefaultFactory;
+#endif // _M_<PLATFORM>
#else
// Make it a "strong" definition if we have no other choice.
ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
#endif
-#endif // _MSC_VER
} // namespace cctz_extension
} // namespace time_internal
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index 134f9f2..66ecb04 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -18,9 +18,9 @@
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_DEFAULT_LINKOPTS",
- "ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
+ "ABSL_TEST_COPTS",
)
package(default_visibility = ["//visibility:public"])
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
index 5ca66e2..85201b4 100644
--- a/absl/types/internal/variant.h
+++ b/absl/types/internal/variant.h
@@ -837,8 +837,8 @@
// NOTE: const& and && are used instead of by-value due to lack of guaranteed
// move elision of C++17. This may have other minor differences, but tests
// pass.
- static SizeT<I> Run(const H&);
- static SizeT<I> Run(H&&);
+ static SizeT<I> Run(const H&, SizeT<I>);
+ static SizeT<I> Run(H&&, SizeT<I>);
};
// The following metafunctions are used in constructor and assignment
@@ -860,7 +860,8 @@
template <class Variant, class T>
struct ConversionIsPossibleImpl<
- Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
+ Variant, T,
+ void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>>
: std::true_type {};
template <class Variant, class T>
@@ -868,8 +869,9 @@
template <class Variant, class T>
struct IndexOfConstructedType<
- Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
- : decltype(ImaginaryFun<Variant>::Run(std::declval<T>())) {};
+ Variant, T,
+ void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>>
+ : decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {})) {};
template <std::size_t... Is>
struct ContainsVariantNPos
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
index b9c9811..d702482 100644
--- a/absl/types/variant_test.cc
+++ b/absl/types/variant_test.cc
@@ -460,6 +460,11 @@
EXPECT_EQ(value.value, mutable_valptr->value);
}
+TEST(VariantTest, AmbiguousValueConstructor) {
+ EXPECT_FALSE((std::is_convertible<int, absl::variant<int, int>>::value));
+ EXPECT_FALSE((std::is_constructible<absl::variant<int, int>, int>::value));
+}
+
TEST(VariantTest, InPlaceType) {
using Var = variant<int, std::string, NonCopyable, std::vector<int>>;