Export of internal Abseil changes.
-- 2f187776e55fe7741882d64aa4fb04d361dcd1da by Shaindel Schwartz <shaindel@google.com>: Fix spaces. PiperOrigin-RevId: 254880665 -- 50a2c390c1e56bec574e9418a6d0c5765f2e1d56 by CJ Johnson <johnsoncj@google.com>: Fixes a ubsan violation bug report: https://github.com/abseil/abseil-cpp/issues/337 PiperOrigin-RevId: 254846112 -- 563fee16ee0ac32a93292c3b2d1cf9543bad4758 by CJ Johnson <johnsoncj@google.com>: In the InlinedVector copy-assignment operator, substitutes-in a call to DeallocateIfAllocated() (which was not previously available) PiperOrigin-RevId: 254835012 -- d07f4d91b43242c5e8bd90f1e93f55f7972eed04 by Shaindel Schwartz <shaindel@google.com>: #336 PiperOrigin-RevId: 254833534 -- 1ad0fe00169a794176605a897f15fad8625339bd by Shaindel Schwartz <shaindel@google.com>: #335 PiperOrigin-RevId: 254826748 -- 436a29591c60c6ac9bb7b98e4906c0a7466611c1 by Shaindel Schwartz <shaindel@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 254820333 -- e782a5387a750319eb6ed5d9927ec2463bd68ebb by CJ Johnson <johnsoncj@google.com>: Updates the definition of InlinedVector::resize(...) to be exception safe and adds exception safety tests PiperOrigin-RevId: 254818993 -- 6d2f8538fb06a09af47232d86b32dfc020b62133 by CJ Johnson <johnsoncj@google.com>: Removes unnecessary transaction object from the implementation of InlinedVector::reserve(n) PiperOrigin-RevId: 254804166 -- 9a3a806702679a7442837089469cf171194da776 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 254489023 -- ded1463ef81f3257645becc6be58df3b433ea21f by CJ Johnson <johnsoncj@google.com>: Updates the definition of InlinedVector::reserve(size_type) to be exception safe and adds exception safety tests PiperOrigin-RevId: 254463057 GitOrigin-RevId: 2f187776e55fe7741882d64aa4fb04d361dcd1da Change-Id: Id41fc5a62c8d71021e803721ecdbfb3ce60ef574
This commit is contained in:
parent
5162fc83d2
commit
d65e19dfcd
11 changed files with 232 additions and 92 deletions
|
@ -467,11 +467,7 @@ class InlinedVector {
|
||||||
if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) {
|
if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) {
|
||||||
inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
|
inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
|
||||||
size());
|
size());
|
||||||
if (storage_.GetIsAllocated()) {
|
storage_.DeallocateIfAllocated();
|
||||||
AllocatorTraits::deallocate(*storage_.GetAllocPtr(),
|
|
||||||
storage_.GetAllocatedData(),
|
|
||||||
storage_.GetAllocatedCapacity());
|
|
||||||
}
|
|
||||||
storage_.MemcpyFrom(other.storage_);
|
storage_.MemcpyFrom(other.storage_);
|
||||||
other.storage_.SetInlinedSize(0);
|
other.storage_.SetInlinedSize(0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -525,49 +521,13 @@ class InlinedVector {
|
||||||
// Resizes the inlined vector to contain `n` elements. If `n` is smaller than
|
// Resizes the inlined vector to contain `n` elements. If `n` is smaller than
|
||||||
// the inlined vector's current size, extra elements are destroyed. If `n` is
|
// the inlined vector's current size, extra elements are destroyed. If `n` is
|
||||||
// larger than the initial size, new elements are value-initialized.
|
// larger than the initial size, new elements are value-initialized.
|
||||||
void resize(size_type n) {
|
void resize(size_type n) { storage_.Resize(DefaultValueAdapter(), n); }
|
||||||
size_type s = size();
|
|
||||||
if (n < s) {
|
|
||||||
erase(begin() + n, end());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reserve(n);
|
|
||||||
assert(capacity() >= n);
|
|
||||||
|
|
||||||
// Fill new space with elements constructed in-place.
|
|
||||||
if (storage_.GetIsAllocated()) {
|
|
||||||
UninitializedFill(storage_.GetAllocatedData() + s,
|
|
||||||
storage_.GetAllocatedData() + n);
|
|
||||||
storage_.SetAllocatedSize(n);
|
|
||||||
} else {
|
|
||||||
UninitializedFill(storage_.GetInlinedData() + s,
|
|
||||||
storage_.GetInlinedData() + n);
|
|
||||||
storage_.SetInlinedSize(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overload of `InlinedVector::resize()` to resize the inlined vector to
|
// Overload of `InlinedVector::resize()` to resize the inlined vector to
|
||||||
// contain `n` elements where, if `n` is larger than `size()`, the new values
|
// contain `n` elements where, if `n` is larger than `size()`, the new values
|
||||||
// will be copy-constructed from `v`.
|
// will be copy-constructed from `v`.
|
||||||
void resize(size_type n, const_reference v) {
|
void resize(size_type n, const_reference v) {
|
||||||
size_type s = size();
|
storage_.Resize(CopyValueAdapter(v), n);
|
||||||
if (n < s) {
|
|
||||||
erase(begin() + n, end());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reserve(n);
|
|
||||||
assert(capacity() >= n);
|
|
||||||
|
|
||||||
// Fill new space with copies of `v`.
|
|
||||||
if (storage_.GetIsAllocated()) {
|
|
||||||
UninitializedFill(storage_.GetAllocatedData() + s,
|
|
||||||
storage_.GetAllocatedData() + n, v);
|
|
||||||
storage_.SetAllocatedSize(n);
|
|
||||||
} else {
|
|
||||||
UninitializedFill(storage_.GetInlinedData() + s,
|
|
||||||
storage_.GetInlinedData() + n, v);
|
|
||||||
storage_.SetInlinedSize(n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `InlinedVector::insert()`
|
// `InlinedVector::insert()`
|
||||||
|
@ -784,22 +744,7 @@ class InlinedVector {
|
||||||
// NOTE: If `n` does not exceed `capacity()`, `reserve()` will have no
|
// NOTE: If `n` does not exceed `capacity()`, `reserve()` will have no
|
||||||
// effects. Otherwise, `reserve()` will reallocate, performing an n-time
|
// effects. Otherwise, `reserve()` will reallocate, performing an n-time
|
||||||
// element-wise move of everything contained.
|
// element-wise move of everything contained.
|
||||||
void reserve(size_type n) {
|
void reserve(size_type n) { storage_.Reserve(n); }
|
||||||
if (n <= capacity()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const size_type s = size();
|
|
||||||
size_type target = (std::max)(static_cast<size_type>(N), n);
|
|
||||||
size_type new_capacity = capacity();
|
|
||||||
while (new_capacity < target) {
|
|
||||||
new_capacity <<= 1;
|
|
||||||
}
|
|
||||||
pointer new_data =
|
|
||||||
AllocatorTraits::allocate(*storage_.GetAllocPtr(), new_capacity);
|
|
||||||
UninitializedCopy(std::make_move_iterator(data()),
|
|
||||||
std::make_move_iterator(data() + s), new_data);
|
|
||||||
ResetAllocation(new_data, new_capacity, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// `InlinedVector::shrink_to_fit()`
|
// `InlinedVector::shrink_to_fit()`
|
||||||
//
|
//
|
||||||
|
|
|
@ -259,6 +259,26 @@ TYPED_TEST(TwoSizeTest, Assign) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(TwoSizeTest, Resize) {
|
||||||
|
using VecT = typename TypeParam::VecT;
|
||||||
|
using value_type = typename VecT::value_type;
|
||||||
|
constexpr static auto from_size = TypeParam::GetSizeAt(0);
|
||||||
|
constexpr static auto to_size = TypeParam::GetSizeAt(1);
|
||||||
|
|
||||||
|
auto tester = testing::MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(VecT{from_size})
|
||||||
|
.WithContracts(InlinedVectorInvariants<VecT>,
|
||||||
|
testing::strong_guarantee);
|
||||||
|
|
||||||
|
EXPECT_TRUE(tester.Test([](VecT* vec) {
|
||||||
|
vec->resize(to_size); //
|
||||||
|
}));
|
||||||
|
|
||||||
|
EXPECT_TRUE(tester.Test([](VecT* vec) {
|
||||||
|
vec->resize(to_size, value_type{}); //
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
TYPED_TEST(OneSizeTest, PopBack) {
|
TYPED_TEST(OneSizeTest, PopBack) {
|
||||||
using VecT = typename TypeParam::VecT;
|
using VecT = typename TypeParam::VecT;
|
||||||
constexpr static auto size = TypeParam::GetSizeAt(0);
|
constexpr static auto size = TypeParam::GetSizeAt(0);
|
||||||
|
@ -285,6 +305,20 @@ TYPED_TEST(OneSizeTest, Clear) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(TwoSizeTest, Reserve) {
|
||||||
|
using VecT = typename TypeParam::VecT;
|
||||||
|
constexpr static auto from_size = TypeParam::GetSizeAt(0);
|
||||||
|
constexpr static auto to_capacity = TypeParam::GetSizeAt(1);
|
||||||
|
|
||||||
|
auto tester = testing::MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(VecT{from_size})
|
||||||
|
.WithContracts(InlinedVectorInvariants<VecT>);
|
||||||
|
|
||||||
|
EXPECT_TRUE(tester.Test([](VecT* vec) {
|
||||||
|
vec->reserve(to_capacity); //
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
TYPED_TEST(OneSizeTest, ShrinkToFit) {
|
TYPED_TEST(OneSizeTest, ShrinkToFit) {
|
||||||
using VecT = typename TypeParam::VecT;
|
using VecT = typename TypeParam::VecT;
|
||||||
constexpr static auto size = TypeParam::GetSizeAt(0);
|
constexpr static auto size = TypeParam::GetSizeAt(0);
|
||||||
|
|
|
@ -47,19 +47,23 @@ template <typename AllocatorType, typename ValueType, typename SizeType>
|
||||||
void DestroyElements(AllocatorType* alloc_ptr, ValueType* destroy_first,
|
void DestroyElements(AllocatorType* alloc_ptr, ValueType* destroy_first,
|
||||||
SizeType destroy_size) {
|
SizeType destroy_size) {
|
||||||
using AllocatorTraits = absl::allocator_traits<AllocatorType>;
|
using AllocatorTraits = absl::allocator_traits<AllocatorType>;
|
||||||
for (SizeType i = 0; i < destroy_size; ++i) {
|
|
||||||
AllocatorTraits::destroy(*alloc_ptr, destroy_first + i);
|
if (destroy_first != nullptr) {
|
||||||
}
|
for (auto i = destroy_size; i != 0;) {
|
||||||
|
--i;
|
||||||
|
AllocatorTraits::destroy(*alloc_ptr, destroy_first + i);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// Overwrite unused memory with `0xab` so we can catch uninitialized usage.
|
// Overwrite unused memory with `0xab` so we can catch uninitialized usage.
|
||||||
//
|
//
|
||||||
// Cast to `void*` to tell the compiler that we don't care that we might be
|
// Cast to `void*` to tell the compiler that we don't care that we might be
|
||||||
// scribbling on a vtable pointer.
|
// scribbling on a vtable pointer.
|
||||||
void* memory = reinterpret_cast<void*>(destroy_first);
|
auto* memory_ptr = static_cast<void*>(destroy_first);
|
||||||
size_t memory_size = sizeof(ValueType) * destroy_size;
|
auto memory_size = sizeof(ValueType) * destroy_size;
|
||||||
std::memset(memory, 0xab, memory_size);
|
std::memset(memory_ptr, 0xab, memory_size);
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename AllocatorType, typename ValueType, typename ValueAdapter,
|
template <typename AllocatorType, typename ValueType, typename ValueAdapter,
|
||||||
|
@ -191,6 +195,46 @@ class AllocationTransaction {
|
||||||
size_type capacity_ = 0;
|
size_type capacity_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename AllocatorType>
|
||||||
|
class ConstructionTransaction {
|
||||||
|
using pointer = typename AllocatorType::pointer;
|
||||||
|
using size_type = typename AllocatorType::size_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConstructionTransaction(AllocatorType* alloc_ptr)
|
||||||
|
: alloc_data_(*alloc_ptr, nullptr) {}
|
||||||
|
|
||||||
|
ConstructionTransaction(const ConstructionTransaction&) = delete;
|
||||||
|
void operator=(const ConstructionTransaction&) = delete;
|
||||||
|
|
||||||
|
template <typename ValueAdapter>
|
||||||
|
void Construct(pointer data, ValueAdapter* values_ptr, size_type size) {
|
||||||
|
inlined_vector_internal::ConstructElements(std::addressof(GetAllocator()),
|
||||||
|
data, values_ptr, size);
|
||||||
|
GetData() = data;
|
||||||
|
GetSize() = size;
|
||||||
|
}
|
||||||
|
void Commit() {
|
||||||
|
GetData() = nullptr;
|
||||||
|
GetSize() = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ConstructionTransaction() {
|
||||||
|
if (GetData() != nullptr) {
|
||||||
|
inlined_vector_internal::DestroyElements(std::addressof(GetAllocator()),
|
||||||
|
GetData(), GetSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
|
||||||
|
pointer& GetData() { return alloc_data_.template get<1>(); }
|
||||||
|
size_type& GetSize() { return size_; }
|
||||||
|
|
||||||
|
container_internal::CompressedTuple<AllocatorType, pointer> alloc_data_;
|
||||||
|
size_type size_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T, size_t N, typename A>
|
template <typename T, size_t N, typename A>
|
||||||
class Storage {
|
class Storage {
|
||||||
public:
|
public:
|
||||||
|
@ -223,6 +267,8 @@ class Storage {
|
||||||
|
|
||||||
using AllocationTransaction =
|
using AllocationTransaction =
|
||||||
inlined_vector_internal::AllocationTransaction<allocator_type>;
|
inlined_vector_internal::AllocationTransaction<allocator_type>;
|
||||||
|
using ConstructionTransaction =
|
||||||
|
inlined_vector_internal::ConstructionTransaction<allocator_type>;
|
||||||
|
|
||||||
Storage() : metadata_() {}
|
Storage() : metadata_() {}
|
||||||
|
|
||||||
|
@ -339,6 +385,11 @@ class Storage {
|
||||||
template <typename ValueAdapter>
|
template <typename ValueAdapter>
|
||||||
void Assign(ValueAdapter values, size_type new_size);
|
void Assign(ValueAdapter values, size_type new_size);
|
||||||
|
|
||||||
|
template <typename ValueAdapter>
|
||||||
|
void Resize(ValueAdapter values, size_type new_size);
|
||||||
|
|
||||||
|
void Reserve(size_type requested_capacity);
|
||||||
|
|
||||||
void ShrinkToFit();
|
void ShrinkToFit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -348,6 +399,16 @@ class Storage {
|
||||||
return metadata_.template get<1>();
|
return metadata_.template get<1>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_type LegacyNextCapacityFrom(size_type current_capacity,
|
||||||
|
size_type requested_capacity) {
|
||||||
|
// TODO(johnsoncj): Get rid of this old behavior.
|
||||||
|
size_type new_capacity = current_capacity;
|
||||||
|
while (new_capacity < requested_capacity) {
|
||||||
|
new_capacity *= 2;
|
||||||
|
}
|
||||||
|
return new_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
using Metadata =
|
using Metadata =
|
||||||
container_internal::CompressedTuple<allocator_type, size_type>;
|
container_internal::CompressedTuple<allocator_type, size_type>;
|
||||||
|
|
||||||
|
@ -434,8 +495,10 @@ auto Storage<T, N, A>::Assign(ValueAdapter values, size_type new_size) -> void {
|
||||||
|
|
||||||
inlined_vector_internal::AssignElements(assign_loop.data(), &values,
|
inlined_vector_internal::AssignElements(assign_loop.data(), &values,
|
||||||
assign_loop.size());
|
assign_loop.size());
|
||||||
|
|
||||||
inlined_vector_internal::ConstructElements(
|
inlined_vector_internal::ConstructElements(
|
||||||
GetAllocPtr(), construct_loop.data(), &values, construct_loop.size());
|
GetAllocPtr(), construct_loop.data(), &values, construct_loop.size());
|
||||||
|
|
||||||
inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
|
inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
|
||||||
destroy_loop.size());
|
destroy_loop.size());
|
||||||
|
|
||||||
|
@ -448,6 +511,88 @@ auto Storage<T, N, A>::Assign(ValueAdapter values, size_type new_size) -> void {
|
||||||
SetSize(new_size);
|
SetSize(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
template <typename ValueAdapter>
|
||||||
|
auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void {
|
||||||
|
StorageView storage_view = MakeStorageView();
|
||||||
|
|
||||||
|
AllocationTransaction allocation_tx(GetAllocPtr());
|
||||||
|
ConstructionTransaction construction_tx(GetAllocPtr());
|
||||||
|
|
||||||
|
IteratorValueAdapter<MoveIterator> move_values(
|
||||||
|
MoveIterator(storage_view.data));
|
||||||
|
|
||||||
|
absl::Span<value_type> construct_loop;
|
||||||
|
absl::Span<value_type> move_construct_loop;
|
||||||
|
absl::Span<value_type> destroy_loop;
|
||||||
|
|
||||||
|
if (new_size > storage_view.capacity) {
|
||||||
|
pointer new_data = allocation_tx.Allocate(
|
||||||
|
LegacyNextCapacityFrom(storage_view.capacity, new_size));
|
||||||
|
|
||||||
|
// Construct new objects in `new_data`
|
||||||
|
construct_loop = {new_data + storage_view.size,
|
||||||
|
new_size - storage_view.size};
|
||||||
|
|
||||||
|
// Move all existing objects into `new_data`
|
||||||
|
move_construct_loop = {new_data, storage_view.size};
|
||||||
|
|
||||||
|
// Destroy all existing objects in `storage_view.data`
|
||||||
|
destroy_loop = {storage_view.data, storage_view.size};
|
||||||
|
} else if (new_size > storage_view.size) {
|
||||||
|
// Construct new objects in `storage_view.data`
|
||||||
|
construct_loop = {storage_view.data + storage_view.size,
|
||||||
|
new_size - storage_view.size};
|
||||||
|
} else {
|
||||||
|
// Destroy end `storage_view.size - new_size` objects in `storage_view.data`
|
||||||
|
destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
|
||||||
|
}
|
||||||
|
|
||||||
|
construction_tx.Construct(construct_loop.data(), &values,
|
||||||
|
construct_loop.size());
|
||||||
|
|
||||||
|
inlined_vector_internal::ConstructElements(
|
||||||
|
GetAllocPtr(), move_construct_loop.data(), &move_values,
|
||||||
|
move_construct_loop.size());
|
||||||
|
|
||||||
|
inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
|
||||||
|
destroy_loop.size());
|
||||||
|
|
||||||
|
construction_tx.Commit();
|
||||||
|
if (allocation_tx.DidAllocate()) {
|
||||||
|
DeallocateIfAllocated();
|
||||||
|
AcquireAllocation(&allocation_tx);
|
||||||
|
SetIsAllocated();
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSize(new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
auto Storage<T, N, A>::Reserve(size_type requested_capacity) -> void {
|
||||||
|
StorageView storage_view = MakeStorageView();
|
||||||
|
|
||||||
|
if (ABSL_PREDICT_FALSE(requested_capacity <= storage_view.capacity)) return;
|
||||||
|
|
||||||
|
AllocationTransaction allocation_tx(GetAllocPtr());
|
||||||
|
|
||||||
|
IteratorValueAdapter<MoveIterator> move_values(
|
||||||
|
MoveIterator(storage_view.data));
|
||||||
|
|
||||||
|
pointer new_data = allocation_tx.Allocate(
|
||||||
|
LegacyNextCapacityFrom(storage_view.capacity, requested_capacity));
|
||||||
|
|
||||||
|
inlined_vector_internal::ConstructElements(GetAllocPtr(), new_data,
|
||||||
|
&move_values, storage_view.size);
|
||||||
|
|
||||||
|
inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
|
||||||
|
storage_view.size);
|
||||||
|
|
||||||
|
DeallocateIfAllocated();
|
||||||
|
AcquireAllocation(&allocation_tx);
|
||||||
|
SetIsAllocated();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, size_t N, typename A>
|
template <typename T, size_t N, typename A>
|
||||||
auto Storage<T, N, A>::ShrinkToFit() -> void {
|
auto Storage<T, N, A>::ShrinkToFit() -> void {
|
||||||
// May only be called on allocated instances!
|
// May only be called on allocated instances!
|
||||||
|
@ -484,6 +629,7 @@ auto Storage<T, N, A>::ShrinkToFit() -> void {
|
||||||
|
|
||||||
inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
|
inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
|
||||||
storage_view.size);
|
storage_view.size);
|
||||||
|
|
||||||
AllocatorTraits::deallocate(*GetAllocPtr(), storage_view.data,
|
AllocatorTraits::deallocate(*GetAllocPtr(), storage_view.data,
|
||||||
storage_view.capacity);
|
storage_view.capacity);
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
|
||||||
//
|
//
|
||||||
// where:
|
// where:
|
||||||
//
|
//
|
||||||
// * `T` is a supported flag type (see `marshalling.h`),
|
// * `T` is a supported flag type (see the list of types in `marshalling.h`),
|
||||||
// * `name` designates the name of the flag (as a global variable
|
// * `name` designates the name of the flag (as a global variable
|
||||||
// `FLAGS_name`),
|
// `FLAGS_name`),
|
||||||
// * `default_value` is an expression holding the default value for this flag
|
// * `default_value` is an expression holding the default value for this flag
|
||||||
|
|
|
@ -8,7 +8,9 @@ load(
|
||||||
"absl_random_randen_copts_init",
|
"absl_random_randen_copts_init",
|
||||||
)
|
)
|
||||||
|
|
||||||
package(default_visibility = ["//absl/random:__pkg__"])
|
package(default_visibility = [
|
||||||
|
"//absl/random:__pkg__",
|
||||||
|
])
|
||||||
|
|
||||||
licenses(["notice"]) # Apache 2.0
|
licenses(["notice"]) # Apache 2.0
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#define ABSL_RANDOM_USE_BCRYPT 1
|
#define ABSL_RANDOM_USE_BCRYPT 1
|
||||||
#pragma comment(lib, "bcrypt.lib")
|
#pragma comment(lib, "bcrypt.lib")
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ABSL_RANDOM_USE_BCRYPT)
|
#if defined(ABSL_RANDOM_USE_BCRYPT)
|
||||||
|
|
|
@ -279,7 +279,7 @@ using civil_second = detail::civil_second;
|
||||||
//
|
//
|
||||||
using detail::weekday;
|
using detail::weekday;
|
||||||
|
|
||||||
// Returns the weekday for the given civil_day.
|
// Returns the weekday for the given civil-time value.
|
||||||
//
|
//
|
||||||
// civil_day a(2015, 8, 13);
|
// civil_day a(2015, 8, 13);
|
||||||
// weekday wd = get_weekday(a); // wd == weekday::thursday
|
// weekday wd = get_weekday(a); // wd == weekday::thursday
|
||||||
|
@ -313,7 +313,7 @@ using detail::get_weekday;
|
||||||
using detail::next_weekday;
|
using detail::next_weekday;
|
||||||
using detail::prev_weekday;
|
using detail::prev_weekday;
|
||||||
|
|
||||||
// Returns the day-of-year for the given civil_day.
|
// Returns the day-of-year for the given civil-time value.
|
||||||
//
|
//
|
||||||
// civil_day a(2015, 1, 1);
|
// civil_day a(2015, 1, 1);
|
||||||
// int yd_jan_1 = get_yearday(a); // yd_jan_1 = 1
|
// int yd_jan_1 = get_yearday(a); // yd_jan_1 = 1
|
||||||
|
|
|
@ -535,7 +535,8 @@ enum class weekday {
|
||||||
sunday,
|
sunday,
|
||||||
};
|
};
|
||||||
|
|
||||||
CONSTEXPR_F weekday get_weekday(const civil_day& cd) noexcept {
|
template <typename T>
|
||||||
|
CONSTEXPR_F weekday get_weekday(const civil_time<T>& ct) noexcept {
|
||||||
CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
|
CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
|
||||||
weekday::monday, weekday::tuesday, weekday::wednesday,
|
weekday::monday, weekday::tuesday, weekday::wednesday,
|
||||||
weekday::thursday, weekday::friday, weekday::saturday,
|
weekday::thursday, weekday::friday, weekday::saturday,
|
||||||
|
@ -546,9 +547,9 @@ CONSTEXPR_F weekday get_weekday(const civil_day& cd) noexcept {
|
||||||
CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
|
CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
|
||||||
-1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
|
-1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
|
||||||
};
|
};
|
||||||
year_t wd = 2400 + (cd.year() % 400) - (cd.month() < 3);
|
year_t wd = 2400 + (ct.year() % 400) - (ct.month() < 3);
|
||||||
wd += wd / 4 - wd / 100 + wd / 400;
|
wd += wd / 4 - wd / 100 + wd / 400;
|
||||||
wd += k_weekday_offsets[cd.month()] + cd.day();
|
wd += k_weekday_offsets[ct.month()] + ct.day();
|
||||||
return k_weekday_by_mon_off[wd % 7 + 6];
|
return k_weekday_by_mon_off[wd % 7 + 6];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,12 +595,13 @@ CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CONSTEXPR_F int get_yearday(const civil_day& cd) noexcept {
|
template <typename T>
|
||||||
|
CONSTEXPR_F int get_yearday(const civil_time<T>& ct) noexcept {
|
||||||
CONSTEXPR_D int k_month_offsets[1 + 12] = {
|
CONSTEXPR_D int k_month_offsets[1 + 12] = {
|
||||||
-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
|
-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
|
||||||
};
|
};
|
||||||
const int feb29 = (cd.month() > 2 && impl::is_leap_year(cd.year()));
|
const int feb29 = (ct.month() > 2 && impl::is_leap_year(ct.year()));
|
||||||
return k_month_offsets[cd.month()] + feb29 + cd.day();
|
return k_month_offsets[ct.month()] + feb29 + ct.day();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -821,6 +821,8 @@ TEST(CivilTime, Properties) {
|
||||||
EXPECT_EQ(4, ss.hour());
|
EXPECT_EQ(4, ss.hour());
|
||||||
EXPECT_EQ(5, ss.minute());
|
EXPECT_EQ(5, ss.minute());
|
||||||
EXPECT_EQ(6, ss.second());
|
EXPECT_EQ(6, ss.second());
|
||||||
|
EXPECT_EQ(weekday::tuesday, get_weekday(ss));
|
||||||
|
EXPECT_EQ(34, get_yearday(ss));
|
||||||
|
|
||||||
civil_minute mm(2015, 2, 3, 4, 5, 6);
|
civil_minute mm(2015, 2, 3, 4, 5, 6);
|
||||||
EXPECT_EQ(2015, mm.year());
|
EXPECT_EQ(2015, mm.year());
|
||||||
|
@ -829,6 +831,8 @@ TEST(CivilTime, Properties) {
|
||||||
EXPECT_EQ(4, mm.hour());
|
EXPECT_EQ(4, mm.hour());
|
||||||
EXPECT_EQ(5, mm.minute());
|
EXPECT_EQ(5, mm.minute());
|
||||||
EXPECT_EQ(0, mm.second());
|
EXPECT_EQ(0, mm.second());
|
||||||
|
EXPECT_EQ(weekday::tuesday, get_weekday(mm));
|
||||||
|
EXPECT_EQ(34, get_yearday(mm));
|
||||||
|
|
||||||
civil_hour hh(2015, 2, 3, 4, 5, 6);
|
civil_hour hh(2015, 2, 3, 4, 5, 6);
|
||||||
EXPECT_EQ(2015, hh.year());
|
EXPECT_EQ(2015, hh.year());
|
||||||
|
@ -837,6 +841,8 @@ TEST(CivilTime, Properties) {
|
||||||
EXPECT_EQ(4, hh.hour());
|
EXPECT_EQ(4, hh.hour());
|
||||||
EXPECT_EQ(0, hh.minute());
|
EXPECT_EQ(0, hh.minute());
|
||||||
EXPECT_EQ(0, hh.second());
|
EXPECT_EQ(0, hh.second());
|
||||||
|
EXPECT_EQ(weekday::tuesday, get_weekday(hh));
|
||||||
|
EXPECT_EQ(34, get_yearday(hh));
|
||||||
|
|
||||||
civil_day d(2015, 2, 3, 4, 5, 6);
|
civil_day d(2015, 2, 3, 4, 5, 6);
|
||||||
EXPECT_EQ(2015, d.year());
|
EXPECT_EQ(2015, d.year());
|
||||||
|
@ -855,6 +861,8 @@ TEST(CivilTime, Properties) {
|
||||||
EXPECT_EQ(0, m.hour());
|
EXPECT_EQ(0, m.hour());
|
||||||
EXPECT_EQ(0, m.minute());
|
EXPECT_EQ(0, m.minute());
|
||||||
EXPECT_EQ(0, m.second());
|
EXPECT_EQ(0, m.second());
|
||||||
|
EXPECT_EQ(weekday::sunday, get_weekday(m));
|
||||||
|
EXPECT_EQ(32, get_yearday(m));
|
||||||
|
|
||||||
civil_year y(2015, 2, 3, 4, 5, 6);
|
civil_year y(2015, 2, 3, 4, 5, 6);
|
||||||
EXPECT_EQ(2015, y.year());
|
EXPECT_EQ(2015, y.year());
|
||||||
|
@ -863,6 +871,8 @@ TEST(CivilTime, Properties) {
|
||||||
EXPECT_EQ(0, y.hour());
|
EXPECT_EQ(0, y.hour());
|
||||||
EXPECT_EQ(0, y.minute());
|
EXPECT_EQ(0, y.minute());
|
||||||
EXPECT_EQ(0, y.second());
|
EXPECT_EQ(0, y.second());
|
||||||
|
EXPECT_EQ(weekday::thursday, get_weekday(y));
|
||||||
|
EXPECT_EQ(1, get_yearday(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CivilTime, OutputStream) {
|
TEST(CivilTime, OutputStream) {
|
||||||
|
|
|
@ -82,7 +82,7 @@ std::tm ToTM(const time_zone::absolute_lookup& al) {
|
||||||
tm.tm_year = static_cast<int>(al.cs.year() - 1900);
|
tm.tm_year = static_cast<int>(al.cs.year() - 1900);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (get_weekday(civil_day(al.cs))) {
|
switch (get_weekday(al.cs)) {
|
||||||
case weekday::sunday:
|
case weekday::sunday:
|
||||||
tm.tm_wday = 0;
|
tm.tm_wday = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -105,7 +105,7 @@ std::tm ToTM(const time_zone::absolute_lookup& al) {
|
||||||
tm.tm_wday = 6;
|
tm.tm_wday = 6;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tm.tm_yday = get_yearday(civil_day(al.cs)) - 1;
|
tm.tm_yday = get_yearday(al.cs) - 1;
|
||||||
tm.tm_isdst = al.is_dst ? 1 : 0;
|
tm.tm_isdst = al.is_dst ? 1 : 0;
|
||||||
return tm;
|
return tm;
|
||||||
}
|
}
|
||||||
|
|
|
@ -836,7 +836,7 @@ TEST(BreakTime, LocalTimeInUTC) {
|
||||||
const time_zone tz = utc_time_zone();
|
const time_zone tz = utc_time_zone();
|
||||||
const auto tp = chrono::system_clock::from_time_t(0);
|
const auto tp = chrono::system_clock::from_time_t(0);
|
||||||
ExpectTime(tp, tz, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
ExpectTime(tp, tz, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||||
EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BreakTime, LocalTimeInUTCUnaligned) {
|
TEST(BreakTime, LocalTimeInUTCUnaligned) {
|
||||||
|
@ -844,7 +844,7 @@ TEST(BreakTime, LocalTimeInUTCUnaligned) {
|
||||||
const auto tp =
|
const auto tp =
|
||||||
chrono::system_clock::from_time_t(0) - chrono::milliseconds(500);
|
chrono::system_clock::from_time_t(0) - chrono::milliseconds(500);
|
||||||
ExpectTime(tp, tz, 1969, 12, 31, 23, 59, 59, 0, false, "UTC");
|
ExpectTime(tp, tz, 1969, 12, 31, 23, 59, 59, 0, false, "UTC");
|
||||||
EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BreakTime, LocalTimePosix) {
|
TEST(BreakTime, LocalTimePosix) {
|
||||||
|
@ -852,7 +852,7 @@ TEST(BreakTime, LocalTimePosix) {
|
||||||
const time_zone tz = utc_time_zone();
|
const time_zone tz = utc_time_zone();
|
||||||
const auto tp = chrono::system_clock::from_time_t(536457599);
|
const auto tp = chrono::system_clock::from_time_t(536457599);
|
||||||
ExpectTime(tp, tz, 1986, 12, 31, 23, 59, 59, 0, false, "UTC");
|
ExpectTime(tp, tz, 1986, 12, 31, 23, 59, 59, 0, false, "UTC");
|
||||||
EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeZoneImpl, LocalTimeInFixed) {
|
TEST(TimeZoneImpl, LocalTimeInFixed) {
|
||||||
|
@ -862,28 +862,28 @@ TEST(TimeZoneImpl, LocalTimeInFixed) {
|
||||||
const auto tp = chrono::system_clock::from_time_t(0);
|
const auto tp = chrono::system_clock::from_time_t(0);
|
||||||
ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false,
|
ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false,
|
||||||
"-083347");
|
"-083347");
|
||||||
EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BreakTime, LocalTimeInNewYork) {
|
TEST(BreakTime, LocalTimeInNewYork) {
|
||||||
const time_zone tz = LoadZone("America/New_York");
|
const time_zone tz = LoadZone("America/New_York");
|
||||||
const auto tp = chrono::system_clock::from_time_t(45);
|
const auto tp = chrono::system_clock::from_time_t(45);
|
||||||
ExpectTime(tp, tz, 1969, 12, 31, 19, 0, 45, -5 * 60 * 60, false, "EST");
|
ExpectTime(tp, tz, 1969, 12, 31, 19, 0, 45, -5 * 60 * 60, false, "EST");
|
||||||
EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BreakTime, LocalTimeInMTV) {
|
TEST(BreakTime, LocalTimeInMTV) {
|
||||||
const time_zone tz = LoadZone("America/Los_Angeles");
|
const time_zone tz = LoadZone("America/Los_Angeles");
|
||||||
const auto tp = chrono::system_clock::from_time_t(1380855729);
|
const auto tp = chrono::system_clock::from_time_t(1380855729);
|
||||||
ExpectTime(tp, tz, 2013, 10, 3, 20, 2, 9, -7 * 60 * 60, true, "PDT");
|
ExpectTime(tp, tz, 2013, 10, 3, 20, 2, 9, -7 * 60 * 60, true, "PDT");
|
||||||
EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BreakTime, LocalTimeInSydney) {
|
TEST(BreakTime, LocalTimeInSydney) {
|
||||||
const time_zone tz = LoadZone("Australia/Sydney");
|
const time_zone tz = LoadZone("Australia/Sydney");
|
||||||
const auto tp = chrono::system_clock::from_time_t(90);
|
const auto tp = chrono::system_clock::from_time_t(90);
|
||||||
ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST");
|
ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST");
|
||||||
EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MakeTime, TimePointResolution) {
|
TEST(MakeTime, TimePointResolution) {
|
||||||
|
@ -1274,10 +1274,10 @@ TEST(TimeZoneEdgeCase, PacificApia) {
|
||||||
// 1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (+14)
|
// 1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (+14)
|
||||||
auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz);
|
auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz);
|
||||||
ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "-10");
|
ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "-10");
|
||||||
EXPECT_EQ(363, get_yearday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(363, get_yearday(convert(tp, tz)));
|
||||||
tp += absl::time_internal::cctz::seconds(1);
|
tp += absl::time_internal::cctz::seconds(1);
|
||||||
ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "+14");
|
ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "+14");
|
||||||
EXPECT_EQ(365, get_yearday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(365, get_yearday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeZoneEdgeCase, AfricaCairo) {
|
TEST(TimeZoneEdgeCase, AfricaCairo) {
|
||||||
|
@ -1399,10 +1399,10 @@ TEST(TimeZoneEdgeCase, NegativeYear) {
|
||||||
const time_zone tz = utc_time_zone();
|
const time_zone tz = utc_time_zone();
|
||||||
auto tp = convert(civil_second(0, 1, 1, 0, 0, 0), tz);
|
auto tp = convert(civil_second(0, 1, 1, 0, 0, 0), tz);
|
||||||
ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
|
ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
|
||||||
EXPECT_EQ(weekday::saturday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::saturday, get_weekday(convert(tp, tz)));
|
||||||
tp -= absl::time_internal::cctz::seconds(1);
|
tp -= absl::time_internal::cctz::seconds(1);
|
||||||
ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC");
|
ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC");
|
||||||
EXPECT_EQ(weekday::friday, get_weekday(civil_day(convert(tp, tz))));
|
EXPECT_EQ(weekday::friday, get_weekday(convert(tp, tz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeZoneEdgeCase, UTC32bitLimit) {
|
TEST(TimeZoneEdgeCase, UTC32bitLimit) {
|
||||||
|
|
Loading…
Reference in a new issue