00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
00031 #define ABSL_CONTAINER_FIXED_ARRAY_H_
00032
00033 #include <algorithm>
00034 #include <array>
00035 #include <cassert>
00036 #include <cstddef>
00037 #include <initializer_list>
00038 #include <iterator>
00039 #include <limits>
00040 #include <memory>
00041 #include <new>
00042 #include <type_traits>
00043
00044 #include "absl/algorithm/algorithm.h"
00045 #include "absl/base/dynamic_annotations.h"
00046 #include "absl/base/internal/throw_delegate.h"
00047 #include "absl/base/macros.h"
00048 #include "absl/base/optimization.h"
00049 #include "absl/base/port.h"
00050 #include "absl/container/internal/compressed_tuple.h"
00051 #include "absl/memory/memory.h"
00052
00053 namespace absl {
00054
00055 constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 template <typename T, size_t N = kFixedArrayUseDefault,
00081 typename A = std::allocator<T>>
00082 class FixedArray {
00083 static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
00084 "Arrays with unknown bounds cannot be used with FixedArray.");
00085
00086 static constexpr size_t kInlineBytesDefault = 256;
00087
00088 using AllocatorTraits = std::allocator_traits<A>;
00089
00090
00091 template <typename Iterator>
00092 using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
00093 typename std::iterator_traits<Iterator>::iterator_category,
00094 std::forward_iterator_tag>::value>;
00095 static constexpr bool NoexceptCopyable() {
00096 return std::is_nothrow_copy_constructible<StorageElement>::value &&
00097 absl::allocator_is_nothrow<allocator_type>::value;
00098 }
00099 static constexpr bool NoexceptMovable() {
00100 return std::is_nothrow_move_constructible<StorageElement>::value &&
00101 absl::allocator_is_nothrow<allocator_type>::value;
00102 }
00103 static constexpr bool DefaultConstructorIsNonTrivial() {
00104 return !absl::is_trivially_default_constructible<StorageElement>::value;
00105 }
00106
00107 public:
00108 using allocator_type = typename AllocatorTraits::allocator_type;
00109 using value_type = typename allocator_type::value_type;
00110 using pointer = typename allocator_type::pointer;
00111 using const_pointer = typename allocator_type::const_pointer;
00112 using reference = typename allocator_type::reference;
00113 using const_reference = typename allocator_type::const_reference;
00114 using size_type = typename allocator_type::size_type;
00115 using difference_type = typename allocator_type::difference_type;
00116 using iterator = pointer;
00117 using const_iterator = const_pointer;
00118 using reverse_iterator = std::reverse_iterator<iterator>;
00119 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
00120
00121 static constexpr size_type inline_elements =
00122 (N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
00123 : static_cast<size_type>(N));
00124
00125 FixedArray(
00126 const FixedArray& other,
00127 const allocator_type& a = allocator_type()) noexcept(NoexceptCopyable())
00128 : FixedArray(other.begin(), other.end(), a) {}
00129
00130 FixedArray(
00131 FixedArray&& other,
00132 const allocator_type& a = allocator_type()) noexcept(NoexceptMovable())
00133 : FixedArray(std::make_move_iterator(other.begin()),
00134 std::make_move_iterator(other.end()), a) {}
00135
00136
00137
00138 explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
00139 : storage_(n, a) {
00140 if (DefaultConstructorIsNonTrivial()) {
00141 memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
00142 storage_.end());
00143 }
00144 }
00145
00146
00147 FixedArray(size_type n, const value_type& val,
00148 const allocator_type& a = allocator_type())
00149 : storage_(n, a) {
00150 memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
00151 storage_.end(), val);
00152 }
00153
00154
00155 FixedArray(std::initializer_list<value_type> init_list,
00156 const allocator_type& a = allocator_type())
00157 : FixedArray(init_list.begin(), init_list.end(), a) {}
00158
00159
00160
00161
00162 template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
00163 FixedArray(Iterator first, Iterator last,
00164 const allocator_type& a = allocator_type())
00165 : storage_(std::distance(first, last), a) {
00166 memory_internal::CopyRange(storage_.alloc(), storage_.begin(), first, last);
00167 }
00168
00169 ~FixedArray() noexcept {
00170 for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
00171 AllocatorTraits::destroy(storage_.alloc(), cur);
00172 }
00173 }
00174
00175
00176
00177 void operator=(FixedArray&&) = delete;
00178 void operator=(const FixedArray&) = delete;
00179
00180
00181
00182
00183 size_type size() const { return storage_.size(); }
00184
00185
00186
00187
00188
00189
00190 constexpr size_type max_size() const {
00191 return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
00192 }
00193
00194
00195
00196
00197 bool empty() const { return size() == 0; }
00198
00199
00200
00201
00202 size_t memsize() const { return size() * sizeof(value_type); }
00203
00204
00205
00206
00207
00208 const_pointer data() const { return AsValueType(storage_.begin()); }
00209
00210
00211
00212
00213 pointer data() { return AsValueType(storage_.begin()); }
00214
00215
00216
00217
00218
00219 reference operator[](size_type i) {
00220 assert(i < size());
00221 return data()[i];
00222 }
00223
00224
00225
00226
00227 const_reference operator[](size_type i) const {
00228 assert(i < size());
00229 return data()[i];
00230 }
00231
00232
00233
00234
00235
00236 reference at(size_type i) {
00237 if (ABSL_PREDICT_FALSE(i >= size())) {
00238 base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
00239 }
00240 return data()[i];
00241 }
00242
00243
00244
00245 const_reference at(size_type i) const {
00246 if (ABSL_PREDICT_FALSE(i >= size())) {
00247 base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
00248 }
00249 return data()[i];
00250 }
00251
00252
00253
00254
00255 reference front() { return *begin(); }
00256
00257
00258
00259 const_reference front() const { return *begin(); }
00260
00261
00262
00263
00264 reference back() { return *(end() - 1); }
00265
00266
00267
00268 const_reference back() const { return *(end() - 1); }
00269
00270
00271
00272
00273 iterator begin() { return data(); }
00274
00275
00276
00277 const_iterator begin() const { return data(); }
00278
00279
00280
00281
00282 const_iterator cbegin() const { return begin(); }
00283
00284
00285
00286
00287 iterator end() { return data() + size(); }
00288
00289
00290
00291 const_iterator end() const { return data() + size(); }
00292
00293
00294
00295
00296 const_iterator cend() const { return end(); }
00297
00298
00299
00300
00301 reverse_iterator rbegin() { return reverse_iterator(end()); }
00302
00303
00304
00305 const_reverse_iterator rbegin() const {
00306 return const_reverse_iterator(end());
00307 }
00308
00309
00310
00311
00312 const_reverse_iterator crbegin() const { return rbegin(); }
00313
00314
00315
00316
00317 reverse_iterator rend() { return reverse_iterator(begin()); }
00318
00319
00320
00321 const_reverse_iterator rend() const {
00322 return const_reverse_iterator(begin());
00323 }
00324
00325
00326
00327
00328 const_reverse_iterator crend() const { return rend(); }
00329
00330
00331
00332
00333 void fill(const value_type& val) { std::fill(begin(), end(), val); }
00334
00335
00336
00337 friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
00338 return absl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
00339 }
00340
00341 friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
00342 return !(lhs == rhs);
00343 }
00344
00345 friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
00346 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
00347 rhs.end());
00348 }
00349
00350 friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
00351 return rhs < lhs;
00352 }
00353
00354 friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
00355 return !(rhs < lhs);
00356 }
00357
00358 friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
00359 return !(lhs < rhs);
00360 }
00361
00362 template <typename H>
00363 friend H AbslHashValue(H h, const FixedArray& v) {
00364 return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
00365 v.size());
00366 }
00367
00368 private:
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 template <typename OuterT = value_type,
00390 typename InnerT = absl::remove_extent_t<OuterT>,
00391 size_t InnerN = std::extent<OuterT>::value>
00392 struct StorageElementWrapper {
00393 InnerT array[InnerN];
00394 };
00395
00396 using StorageElement =
00397 absl::conditional_t<std::is_array<value_type>::value,
00398 StorageElementWrapper<value_type>, value_type>;
00399 using StorageElementBuffer =
00400 absl::aligned_storage_t<sizeof(StorageElement), alignof(StorageElement)>;
00401
00402 static pointer AsValueType(pointer ptr) { return ptr; }
00403 static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
00404 return std::addressof(ptr->array);
00405 }
00406
00407 static_assert(sizeof(StorageElement) == sizeof(value_type), "");
00408 static_assert(alignof(StorageElement) == alignof(value_type), "");
00409
00410 struct NonEmptyInlinedStorage {
00411 StorageElement* data() {
00412 return reinterpret_cast<StorageElement*>(inlined_storage_.data());
00413 }
00414
00415 #ifdef ADDRESS_SANITIZER
00416 void* RedzoneBegin() { return &redzone_begin_; }
00417 void* RedzoneEnd() { return &redzone_end_ + 1; }
00418 #endif // ADDRESS_SANITIZER
00419
00420 void AnnotateConstruct(size_type);
00421 void AnnotateDestruct(size_type);
00422
00423 ADDRESS_SANITIZER_REDZONE(redzone_begin_);
00424 std::array<StorageElementBuffer, inline_elements> inlined_storage_;
00425 ADDRESS_SANITIZER_REDZONE(redzone_end_);
00426 };
00427
00428 struct EmptyInlinedStorage {
00429 StorageElement* data() { return nullptr; }
00430 void AnnotateConstruct(size_type) {}
00431 void AnnotateDestruct(size_type) {}
00432 };
00433
00434 using InlinedStorage =
00435 absl::conditional_t<inline_elements == 0, EmptyInlinedStorage,
00436 NonEmptyInlinedStorage>;
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 class Storage : public InlinedStorage {
00447 public:
00448 Storage(size_type n, const allocator_type& a)
00449 : size_alloc_(n, a), data_(InitializeData()) {}
00450
00451 ~Storage() noexcept {
00452 if (UsingInlinedStorage(size())) {
00453 InlinedStorage::AnnotateDestruct(size());
00454 } else {
00455 AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
00456 }
00457 }
00458
00459 size_type size() const { return size_alloc_.template get<0>(); }
00460 StorageElement* begin() const { return data_; }
00461 StorageElement* end() const { return begin() + size(); }
00462 allocator_type& alloc() {
00463 return size_alloc_.template get<1>();
00464 }
00465
00466 private:
00467 static bool UsingInlinedStorage(size_type n) {
00468 return n <= inline_elements;
00469 }
00470
00471 StorageElement* InitializeData() {
00472 if (UsingInlinedStorage(size())) {
00473 InlinedStorage::AnnotateConstruct(size());
00474 return InlinedStorage::data();
00475 } else {
00476 return reinterpret_cast<StorageElement*>(
00477 AllocatorTraits::allocate(alloc(), size()));
00478 }
00479 }
00480
00481
00482 container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
00483 StorageElement* data_;
00484 };
00485
00486 Storage storage_;
00487 };
00488
00489 template <typename T, size_t N, typename A>
00490 constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
00491
00492 template <typename T, size_t N, typename A>
00493 constexpr typename FixedArray<T, N, A>::size_type
00494 FixedArray<T, N, A>::inline_elements;
00495
00496 template <typename T, size_t N, typename A>
00497 void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
00498 typename FixedArray<T, N, A>::size_type n) {
00499 #ifdef ADDRESS_SANITIZER
00500 if (!n) return;
00501 ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n);
00502 ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin());
00503 #endif // ADDRESS_SANITIZER
00504 static_cast<void>(n);
00505 }
00506
00507 template <typename T, size_t N, typename A>
00508 void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
00509 typename FixedArray<T, N, A>::size_type n) {
00510 #ifdef ADDRESS_SANITIZER
00511 if (!n) return;
00512 ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd());
00513 ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data());
00514 #endif // ADDRESS_SANITIZER
00515 static_cast<void>(n);
00516 }
00517 }
00518
00519 #endif // ABSL_CONTAINER_FIXED_ARRAY_H_