File indexing completed on 2025-01-18 09:27:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
0031 #define ABSL_CONTAINER_FIXED_ARRAY_H_
0032
0033 #include <algorithm>
0034 #include <cassert>
0035 #include <cstddef>
0036 #include <initializer_list>
0037 #include <iterator>
0038 #include <limits>
0039 #include <memory>
0040 #include <new>
0041 #include <type_traits>
0042
0043 #include "absl/algorithm/algorithm.h"
0044 #include "absl/base/config.h"
0045 #include "absl/base/dynamic_annotations.h"
0046 #include "absl/base/internal/throw_delegate.h"
0047 #include "absl/base/macros.h"
0048 #include "absl/base/optimization.h"
0049 #include "absl/base/port.h"
0050 #include "absl/container/internal/compressed_tuple.h"
0051 #include "absl/memory/memory.h"
0052
0053 namespace absl {
0054 ABSL_NAMESPACE_BEGIN
0055
0056 constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075 template <typename T, size_t N = kFixedArrayUseDefault,
0076 typename A = std::allocator<T>>
0077 class FixedArray {
0078 static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
0079 "Arrays with unknown bounds cannot be used with FixedArray.");
0080
0081 static constexpr size_t kInlineBytesDefault = 256;
0082
0083 using AllocatorTraits = std::allocator_traits<A>;
0084
0085
0086 template <typename Iterator>
0087 using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
0088 typename std::iterator_traits<Iterator>::iterator_category,
0089 std::forward_iterator_tag>::value>;
0090 static constexpr bool NoexceptCopyable() {
0091 return std::is_nothrow_copy_constructible<StorageElement>::value &&
0092 absl::allocator_is_nothrow<allocator_type>::value;
0093 }
0094 static constexpr bool NoexceptMovable() {
0095 return std::is_nothrow_move_constructible<StorageElement>::value &&
0096 absl::allocator_is_nothrow<allocator_type>::value;
0097 }
0098 static constexpr bool DefaultConstructorIsNonTrivial() {
0099 return !absl::is_trivially_default_constructible<StorageElement>::value;
0100 }
0101
0102 public:
0103 using allocator_type = typename AllocatorTraits::allocator_type;
0104 using value_type = typename AllocatorTraits::value_type;
0105 using pointer = typename AllocatorTraits::pointer;
0106 using const_pointer = typename AllocatorTraits::const_pointer;
0107 using reference = value_type&;
0108 using const_reference = const value_type&;
0109 using size_type = typename AllocatorTraits::size_type;
0110 using difference_type = typename AllocatorTraits::difference_type;
0111 using iterator = pointer;
0112 using const_iterator = const_pointer;
0113 using reverse_iterator = std::reverse_iterator<iterator>;
0114 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0115
0116 static constexpr size_type inline_elements =
0117 (N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
0118 : static_cast<size_type>(N));
0119
0120 FixedArray(const FixedArray& other) noexcept(NoexceptCopyable())
0121 : FixedArray(other,
0122 AllocatorTraits::select_on_container_copy_construction(
0123 other.storage_.alloc())) {}
0124
0125 FixedArray(const FixedArray& other,
0126 const allocator_type& a) noexcept(NoexceptCopyable())
0127 : FixedArray(other.begin(), other.end(), a) {}
0128
0129 FixedArray(FixedArray&& other) noexcept(NoexceptMovable())
0130 : FixedArray(std::move(other), other.storage_.alloc()) {}
0131
0132 FixedArray(FixedArray&& other,
0133 const allocator_type& a) noexcept(NoexceptMovable())
0134 : FixedArray(std::make_move_iterator(other.begin()),
0135 std::make_move_iterator(other.end()), a) {}
0136
0137
0138
0139 explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
0140 : storage_(n, a) {
0141 if (DefaultConstructorIsNonTrivial()) {
0142 memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
0143 storage_.end());
0144 }
0145 }
0146
0147
0148 FixedArray(size_type n, const value_type& val,
0149 const allocator_type& a = allocator_type())
0150 : storage_(n, a) {
0151 memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
0152 storage_.end(), val);
0153 }
0154
0155
0156 FixedArray(std::initializer_list<value_type> init_list,
0157 const allocator_type& a = allocator_type())
0158 : FixedArray(init_list.begin(), init_list.end(), a) {}
0159
0160
0161
0162
0163 template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
0164 FixedArray(Iterator first, Iterator last,
0165 const allocator_type& a = allocator_type())
0166 : storage_(std::distance(first, last), a) {
0167 memory_internal::CopyRange(storage_.alloc(), storage_.begin(), first, last);
0168 }
0169
0170 ~FixedArray() noexcept {
0171 for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
0172 AllocatorTraits::destroy(storage_.alloc(), cur);
0173 }
0174 }
0175
0176
0177
0178 void operator=(FixedArray&&) = delete;
0179 void operator=(const FixedArray&) = delete;
0180
0181
0182
0183
0184 size_type size() const { return storage_.size(); }
0185
0186
0187
0188
0189
0190
0191 constexpr size_type max_size() const {
0192 return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
0193 }
0194
0195
0196
0197
0198 bool empty() const { return size() == 0; }
0199
0200
0201
0202
0203 size_t memsize() const { return size() * sizeof(value_type); }
0204
0205
0206
0207
0208
0209 const_pointer data() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0210 return AsValueType(storage_.begin());
0211 }
0212
0213
0214
0215
0216 pointer data() ABSL_ATTRIBUTE_LIFETIME_BOUND {
0217 return AsValueType(storage_.begin());
0218 }
0219
0220
0221
0222
0223
0224 reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
0225 ABSL_HARDENING_ASSERT(i < size());
0226 return data()[i];
0227 }
0228
0229
0230
0231
0232 const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0233 ABSL_HARDENING_ASSERT(i < size());
0234 return data()[i];
0235 }
0236
0237
0238
0239
0240
0241 reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
0242 if (ABSL_PREDICT_FALSE(i >= size())) {
0243 base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
0244 }
0245 return data()[i];
0246 }
0247
0248
0249
0250 const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0251 if (ABSL_PREDICT_FALSE(i >= size())) {
0252 base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
0253 }
0254 return data()[i];
0255 }
0256
0257
0258
0259
0260 reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND {
0261 ABSL_HARDENING_ASSERT(!empty());
0262 return data()[0];
0263 }
0264
0265
0266
0267 const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0268 ABSL_HARDENING_ASSERT(!empty());
0269 return data()[0];
0270 }
0271
0272
0273
0274
0275 reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND {
0276 ABSL_HARDENING_ASSERT(!empty());
0277 return data()[size() - 1];
0278 }
0279
0280
0281
0282 const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0283 ABSL_HARDENING_ASSERT(!empty());
0284 return data()[size() - 1];
0285 }
0286
0287
0288
0289
0290 iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
0291
0292
0293
0294 const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
0295
0296
0297
0298
0299 const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0300 return begin();
0301 }
0302
0303
0304
0305
0306 iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data() + size(); }
0307
0308
0309
0310 const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0311 return data() + size();
0312 }
0313
0314
0315
0316
0317 const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
0318
0319
0320
0321
0322 reverse_iterator rbegin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
0323 return reverse_iterator(end());
0324 }
0325
0326
0327
0328 const_reverse_iterator rbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0329 return const_reverse_iterator(end());
0330 }
0331
0332
0333
0334
0335 const_reverse_iterator crbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0336 return rbegin();
0337 }
0338
0339
0340
0341
0342 reverse_iterator rend() ABSL_ATTRIBUTE_LIFETIME_BOUND {
0343 return reverse_iterator(begin());
0344 }
0345
0346
0347
0348 const_reverse_iterator rend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0349 return const_reverse_iterator(begin());
0350 }
0351
0352
0353
0354
0355 const_reverse_iterator crend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
0356 return rend();
0357 }
0358
0359
0360
0361
0362 void fill(const value_type& val) { std::fill(begin(), end(), val); }
0363
0364
0365
0366 friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
0367 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
0368 }
0369
0370 friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
0371 return !(lhs == rhs);
0372 }
0373
0374 friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
0375 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
0376 rhs.end());
0377 }
0378
0379 friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
0380 return rhs < lhs;
0381 }
0382
0383 friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
0384 return !(rhs < lhs);
0385 }
0386
0387 friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
0388 return !(lhs < rhs);
0389 }
0390
0391 template <typename H>
0392 friend H AbslHashValue(H h, const FixedArray& v) {
0393 return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
0394 v.size());
0395 }
0396
0397 private:
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418 template <typename OuterT, typename InnerT = absl::remove_extent_t<OuterT>,
0419 size_t InnerN = std::extent<OuterT>::value>
0420 struct StorageElementWrapper {
0421 InnerT array[InnerN];
0422 };
0423
0424 using StorageElement =
0425 absl::conditional_t<std::is_array<value_type>::value,
0426 StorageElementWrapper<value_type>, value_type>;
0427
0428 static pointer AsValueType(pointer ptr) { return ptr; }
0429 static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
0430 return std::addressof(ptr->array);
0431 }
0432
0433 static_assert(sizeof(StorageElement) == sizeof(value_type), "");
0434 static_assert(alignof(StorageElement) == alignof(value_type), "");
0435
0436 class NonEmptyInlinedStorage {
0437 public:
0438 StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
0439 void AnnotateConstruct(size_type n);
0440 void AnnotateDestruct(size_type n);
0441
0442 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0443 void* RedzoneBegin() { return &redzone_begin_; }
0444 void* RedzoneEnd() { return &redzone_end_ + 1; }
0445 #endif
0446
0447 private:
0448 ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
0449 alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
0450 ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
0451 };
0452
0453 class EmptyInlinedStorage {
0454 public:
0455 StorageElement* data() { return nullptr; }
0456 void AnnotateConstruct(size_type) {}
0457 void AnnotateDestruct(size_type) {}
0458 };
0459
0460 using InlinedStorage =
0461 absl::conditional_t<inline_elements == 0, EmptyInlinedStorage,
0462 NonEmptyInlinedStorage>;
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472 class Storage : public InlinedStorage {
0473 public:
0474 Storage(size_type n, const allocator_type& a)
0475 : size_alloc_(n, a), data_(InitializeData()) {}
0476
0477 ~Storage() noexcept {
0478 if (UsingInlinedStorage(size())) {
0479 InlinedStorage::AnnotateDestruct(size());
0480 } else {
0481 AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
0482 }
0483 }
0484
0485 size_type size() const { return size_alloc_.template get<0>(); }
0486 StorageElement* begin() const { return data_; }
0487 StorageElement* end() const { return begin() + size(); }
0488 allocator_type& alloc() { return size_alloc_.template get<1>(); }
0489 const allocator_type& alloc() const {
0490 return size_alloc_.template get<1>();
0491 }
0492
0493 private:
0494 static bool UsingInlinedStorage(size_type n) {
0495 return n <= inline_elements;
0496 }
0497
0498 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0499 ABSL_ATTRIBUTE_NOINLINE
0500 #endif
0501 StorageElement* InitializeData() {
0502 if (UsingInlinedStorage(size())) {
0503 InlinedStorage::AnnotateConstruct(size());
0504 return InlinedStorage::data();
0505 } else {
0506 return reinterpret_cast<StorageElement*>(
0507 AllocatorTraits::allocate(alloc(), size()));
0508 }
0509 }
0510
0511
0512 container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
0513 StorageElement* data_;
0514 };
0515
0516 Storage storage_;
0517 };
0518
0519 #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
0520 template <typename T, size_t N, typename A>
0521 constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
0522
0523 template <typename T, size_t N, typename A>
0524 constexpr typename FixedArray<T, N, A>::size_type
0525 FixedArray<T, N, A>::inline_elements;
0526 #endif
0527
0528 template <typename T, size_t N, typename A>
0529 void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
0530 typename FixedArray<T, N, A>::size_type n) {
0531 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0532 if (!n) return;
0533 ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
0534 data() + n);
0535 ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
0536 RedzoneBegin());
0537 #endif
0538 static_cast<void>(n);
0539 }
0540
0541 template <typename T, size_t N, typename A>
0542 void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
0543 typename FixedArray<T, N, A>::size_type n) {
0544 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0545 if (!n) return;
0546 ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
0547 RedzoneEnd());
0548 ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
0549 data());
0550 #endif
0551 static_cast<void>(n);
0552 }
0553 ABSL_NAMESPACE_END
0554 }
0555
0556 #endif