| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #ifndef CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_ |
| | #define CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_ |
| |
|
| | #include <Eigen/Core> |
| | #include <algorithm> |
| | #include <array> |
| | #include <cstddef> |
| | #include <memory> |
| | #include <tuple> |
| | #include <type_traits> |
| |
|
| | #include "ceres/internal/memory.h" |
| | #include "glog/logging.h" |
| |
|
| | namespace ceres { |
| | namespace internal { |
| |
|
| | constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | template <typename T> |
| | using FixedArrayDefaultAllocator = |
| | typename std::conditional<std::is_trivial<T>::value, |
| | std::allocator<T>, |
| | Eigen::aligned_allocator<T>>::type; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | template <typename T, |
| | size_t N = kFixedArrayUseDefault, |
| | typename A = FixedArrayDefaultAllocator<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 = typename std::enable_if<std::is_convertible< |
| | typename std::iterator_traits<Iterator>::iterator_category, |
| | std::forward_iterator_tag>::value>::type; |
| | static constexpr bool DefaultConstructorIsNonTrivial() { |
| | return !std::is_trivially_default_constructible<StorageElement>::value; |
| | } |
| |
|
| | 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, |
| | const allocator_type& a = allocator_type()) |
| | : FixedArray(other.begin(), other.end(), a) {} |
| |
|
| | FixedArray(FixedArray&& other, const allocator_type& a = allocator_type()) |
| | : FixedArray(std::make_move_iterator(other.begin()), |
| | std::make_move_iterator(other.end()), |
| | a) {} |
| |
|
| | |
| | |
| | explicit FixedArray(size_type n, const allocator_type& a = allocator_type()) |
| | : storage_(n, a) { |
| | if (DefaultConstructorIsNonTrivial()) { |
| | ConstructRange(storage_.alloc(), storage_.begin(), storage_.end()); |
| | } |
| | } |
| |
|
| | |
| | FixedArray(size_type n, |
| | const value_type& val, |
| | const allocator_type& a = allocator_type()) |
| | : storage_(n, a) { |
| | ConstructRange(storage_.alloc(), storage_.begin(), storage_.end(), val); |
| | } |
| |
|
| | |
| | FixedArray(std::initializer_list<value_type> init_list, |
| | const allocator_type& a = allocator_type()) |
| | : FixedArray(init_list.begin(), init_list.end(), a) {} |
| |
|
| | |
| | |
| | |
| | template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr> |
| | FixedArray(Iterator first, |
| | Iterator last, |
| | const allocator_type& a = allocator_type()) |
| | : storage_(std::distance(first, last), a) { |
| | CopyRange(storage_.alloc(), storage_.begin(), first, last); |
| | } |
| |
|
| | ~FixedArray() noexcept { |
| | for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) { |
| | AllocatorTraits::destroy(storage_.alloc(), cur); |
| | } |
| | } |
| |
|
| | |
| | |
| | void operator=(FixedArray&&) = delete; |
| | void operator=(const FixedArray&) = delete; |
| |
|
| | |
| | |
| | |
| | size_type size() const { return storage_.size(); } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | constexpr size_type max_size() const { |
| | return (std::numeric_limits<difference_type>::max)() / sizeof(value_type); |
| | } |
| |
|
| | |
| | |
| | |
| | bool empty() const { return size() == 0; } |
| |
|
| | |
| | |
| | |
| | size_t memsize() const { return size() * sizeof(value_type); } |
| |
|
| | |
| | |
| | |
| | |
| | const_pointer data() const { return AsValueType(storage_.begin()); } |
| |
|
| | |
| | |
| | |
| | pointer data() { return AsValueType(storage_.begin()); } |
| |
|
| | |
| | |
| | |
| | |
| | reference operator[](size_type i) { |
| | DCHECK_LT(i, size()); |
| | return data()[i]; |
| | } |
| |
|
| | |
| | |
| | |
| | const_reference operator[](size_type i) const { |
| | DCHECK_LT(i, size()); |
| | return data()[i]; |
| | } |
| |
|
| | |
| | |
| | |
| | reference front() { return *begin(); } |
| |
|
| | |
| | |
| | const_reference front() const { return *begin(); } |
| |
|
| | |
| | |
| | |
| | reference back() { return *(end() - 1); } |
| |
|
| | |
| | |
| | const_reference back() const { return *(end() - 1); } |
| |
|
| | |
| | |
| | |
| | iterator begin() { return data(); } |
| |
|
| | |
| | |
| | const_iterator begin() const { return data(); } |
| |
|
| | |
| | |
| | |
| | const_iterator cbegin() const { return begin(); } |
| |
|
| | |
| | |
| | |
| | iterator end() { return data() + size(); } |
| |
|
| | |
| | |
| | const_iterator end() const { return data() + size(); } |
| |
|
| | |
| | |
| | |
| | const_iterator cend() const { return end(); } |
| |
|
| | |
| | |
| | |
| | reverse_iterator rbegin() { return reverse_iterator(end()); } |
| |
|
| | |
| | |
| | const_reverse_iterator rbegin() const { |
| | return const_reverse_iterator(end()); |
| | } |
| |
|
| | |
| | |
| | |
| | const_reverse_iterator crbegin() const { return rbegin(); } |
| |
|
| | |
| | |
| | |
| | reverse_iterator rend() { return reverse_iterator(begin()); } |
| |
|
| | |
| | |
| | const_reverse_iterator rend() const { |
| | return const_reverse_iterator(begin()); |
| | } |
| |
|
| | |
| | |
| | |
| | const_reverse_iterator crend() const { return rend(); } |
| |
|
| | |
| | |
| | |
| | void fill(const value_type& val) { std::fill(begin(), end(), 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); |
| | } |
| |
|
| | private: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | template <typename OuterT, |
| | typename InnerT = typename std::remove_extent<OuterT>::type, |
| | size_t InnerN = std::extent<OuterT>::value> |
| | struct StorageElementWrapper { |
| | InnerT array[InnerN]; |
| | }; |
| |
|
| | using StorageElement = |
| | typename std::conditional<std::is_array<value_type>::value, |
| | StorageElementWrapper<value_type>, |
| | value_type>::type; |
| |
|
| | static pointer AsValueType(pointer ptr) { return ptr; } |
| | static pointer AsValueType(StorageElementWrapper<value_type>* ptr) { |
| | return std::addressof(ptr->array); |
| | } |
| |
|
| | 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) {} |
| | void AnnotateDestruct(size_type) {} |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | private: |
| | |
| | alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])]; |
| | |
| | }; |
| |
|
| | class EmptyInlinedStorage { |
| | public: |
| | StorageElement* data() { return nullptr; } |
| | void AnnotateConstruct(size_type) {} |
| | void AnnotateDestruct(size_type) {} |
| | }; |
| |
|
| | using InlinedStorage = |
| | typename std::conditional<inline_elements == 0, |
| | EmptyInlinedStorage, |
| | NonEmptyInlinedStorage>::type; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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 std::get<0>(size_alloc_); } |
| | StorageElement* begin() const { return data_; } |
| | StorageElement* end() const { return begin() + size(); } |
| | allocator_type& alloc() { return std::get<1>(size_alloc_); } |
| |
|
| | private: |
| | static bool UsingInlinedStorage(size_type n) { |
| | return n <= inline_elements; |
| | } |
| |
|
| | StorageElement* InitializeData() { |
| | if (UsingInlinedStorage(size())) { |
| | InlinedStorage::AnnotateConstruct(size()); |
| | return InlinedStorage::data(); |
| | } else { |
| | return reinterpret_cast<StorageElement*>( |
| | AllocatorTraits::allocate(alloc(), size())); |
| | } |
| | } |
| |
|
| | |
| | |
| | std::tuple<size_type, allocator_type> size_alloc_; |
| | StorageElement* data_; |
| | }; |
| |
|
| | Storage storage_; |
| | }; |
| |
|
| | 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 |
| |
|