#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
#define ABSL_CONTAINER_FIXED_ARRAY_H_
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <limits>
#include <memory>
#include <new>
#include <type_traits>
#include "absl/algorithm/algorithm.h"
#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/memory/memory.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
constexpr static auto kFixedArrayUseDefault = …;
template <typename T, size_t N = kFixedArrayUseDefault,
typename A = std::allocator<T>>
class FixedArray {
static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
"Arrays with unknown bounds cannot be used with FixedArray.");
static constexpr size_t kInlineBytesDefault = 256;
using AllocatorTraits = std::allocator_traits<A>;
template <typename Iterator>
using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
typename std::iterator_traits<Iterator>::iterator_category,
std::forward_iterator_tag>::value>;
static constexpr bool NoexceptCopyable() { … }
static constexpr bool NoexceptMovable() { … }
static constexpr bool DefaultConstructorIsNonTrivial() { … }
public:
using allocator_type = typename AllocatorTraits::allocator_type;
using value_type = typename AllocatorTraits::value_type;
using pointer = typename AllocatorTraits::pointer;
using const_pointer = typename AllocatorTraits::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = typename AllocatorTraits::size_type;
using difference_type = typename AllocatorTraits::difference_type;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
static constexpr size_type inline_elements =
(N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
: static_cast<size_type>(N));
FixedArray(const FixedArray& other) noexcept(NoexceptCopyable())
: … { … }
FixedArray(const FixedArray& other,
const allocator_type& a) noexcept(NoexceptCopyable())
: … { … }
FixedArray(FixedArray&& other) noexcept(NoexceptMovable())
: … { … }
FixedArray(FixedArray&& other,
const allocator_type& a) noexcept(NoexceptMovable())
: … { … }
explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
: … { … }
FixedArray(size_type n, const value_type& val,
const allocator_type& a = allocator_type())
: … { … }
FixedArray(std::initializer_list<value_type> init_list,
const allocator_type& a = allocator_type())
: … { … }
template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
FixedArray(Iterator first, Iterator last,
const allocator_type& a = allocator_type())
: storage_(std::distance(first, last), a) { … }
~FixedArray() noexcept { … }
void operator=(FixedArray&&) = delete;
void operator=(const FixedArray&) = delete;
size_type size() const { … }
constexpr size_type max_size() const { … }
bool empty() const { … }
size_t memsize() const { … }
const_pointer data() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
pointer data() ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
reverse_iterator rbegin() ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_reverse_iterator rbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_reverse_iterator crbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
reverse_iterator rend() ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_reverse_iterator rend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
const_reverse_iterator crend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { … }
void fill(const value_type& val) { … }
friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
return !(lhs == rhs);
}
friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end());
}
friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
return rhs < lhs;
}
friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
return !(rhs < lhs);
}
friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
return !(lhs < rhs);
}
template <typename H>
friend H AbslHashValue(H h, const FixedArray& v) { … }
private:
template <typename OuterT, typename InnerT = absl::remove_extent_t<OuterT>,
size_t InnerN = std::extent<OuterT>::value>
struct StorageElementWrapper {
InnerT array[InnerN];
};
using StorageElement =
absl::conditional_t<std::is_array<value_type>::value,
StorageElementWrapper<value_type>, value_type>;
static pointer AsValueType(pointer ptr) { … }
static pointer AsValueType(StorageElementWrapper<value_type>* ptr) { … }
static_assert(sizeof(StorageElement) == sizeof(value_type), "");
static_assert(alignof(StorageElement) == alignof(value_type), "");
class NonEmptyInlinedStorage {
public:
StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
void AnnotateConstruct(size_type n);
void AnnotateDestruct(size_type n);
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
void* RedzoneBegin() { return &redzone_begin_; }
void* RedzoneEnd() { return &redzone_end_ + 1; }
#endif
private:
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
};
class EmptyInlinedStorage {
public:
StorageElement* data() { return nullptr; }
void AnnotateConstruct(size_type) {}
void AnnotateDestruct(size_type) {}
};
using InlinedStorage =
absl::conditional_t<inline_elements == 0, EmptyInlinedStorage,
NonEmptyInlinedStorage>;
class Storage : public InlinedStorage {
public:
Storage(size_type n, const allocator_type& a)
: size_alloc_(n, a), data_(InitializeData()) {}
~Storage() noexcept {
if (UsingInlinedStorage(size())) {
InlinedStorage::AnnotateDestruct(size());
} else {
AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
}
}
size_type size() const { return size_alloc_.template get<0>(); }
StorageElement* begin() const { return data_; }
StorageElement* end() const { return begin() + size(); }
allocator_type& alloc() { return size_alloc_.template get<1>(); }
const allocator_type& alloc() const {
return size_alloc_.template get<1>();
}
private:
static bool UsingInlinedStorage(size_type n) {
return n <= inline_elements;
}
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
ABSL_ATTRIBUTE_NOINLINE
#endif
StorageElement* InitializeData() {
if (UsingInlinedStorage(size())) {
InlinedStorage::AnnotateConstruct(size());
return InlinedStorage::data();
} else {
return reinterpret_cast<StorageElement*>(
AllocatorTraits::allocate(alloc(), size()));
}
}
container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
StorageElement* data_;
};
Storage storage_;
};
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
template <typename T, size_t N, typename A>
constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
template <typename T, size_t N, typename A>
constexpr typename FixedArray<T, N, A>::size_type
FixedArray<T, N, A>::inline_elements;
#endif
template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
typename FixedArray<T, N, A>::size_type n) { … }
template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
typename FixedArray<T, N, A>::size_type n) { … }
ABSL_NAMESPACE_END
}
#endif