ceres::internal::FixedArray -> absl::FixedArray

Ceres Solver was using an old forked version of FixedArray,
now that we are using absl, we can use the official version
that ships with it.

Change-Id: Ic88d7f6e8a49b928d611f7cbb04172452b322b01
diff --git a/include/ceres/autodiff_first_order_function.h b/include/ceres/autodiff_first_order_function.h
index 6cd1b13..2dca8f3 100644
--- a/include/ceres/autodiff_first_order_function.h
+++ b/include/ceres/autodiff_first_order_function.h
@@ -34,9 +34,9 @@
 #include <memory>
 #include <type_traits>
 
+#include "absl/container/fixed_array.h"
 #include "ceres/first_order_function.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/jet.h"
 #include "ceres/types.h"
 
@@ -131,7 +131,7 @@
     }
 
     using JetT = Jet<double, kNumParameters>;
-    internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(kNumParameters);
+    absl::FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(kNumParameters);
     for (int i = 0; i < kNumParameters; ++i) {
       x[i].a = parameters[i];
       x[i].v.setZero();
diff --git a/include/ceres/dynamic_autodiff_cost_function.h b/include/ceres/dynamic_autodiff_cost_function.h
index 7b4e876..7efdad0 100644
--- a/include/ceres/dynamic_autodiff_cost_function.h
+++ b/include/ceres/dynamic_autodiff_cost_function.h
@@ -38,9 +38,9 @@
 #include <type_traits>
 #include <vector>
 
+#include "absl/container/fixed_array.h"
 #include "absl/log/check.h"
 #include "ceres/dynamic_cost_function.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/jet.h"
 #include "ceres/types.h"
 
@@ -149,14 +149,13 @@
 
     // Allocate scratch space for the strided evaluation.
     using JetT = Jet<double, Stride>;
-    internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> input_jets(
-        num_parameters);
-    internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> output_jets(
+    absl::FixedArray<JetT, (256 * 7) / sizeof(JetT)> input_jets(num_parameters);
+    absl::FixedArray<JetT, (256 * 7) / sizeof(JetT)> output_jets(
         num_residuals());
 
     // Make the parameter pack that is sent to the functor (reused).
-    internal::FixedArray<Jet<double, Stride>*> jet_parameters(
-        num_parameter_blocks, nullptr);
+    absl::FixedArray<Jet<double, Stride>*> jet_parameters(num_parameter_blocks,
+                                                          nullptr);
     int num_active_parameters = 0;
 
     // To handle constant parameters between non-constant parameter blocks, the
diff --git a/include/ceres/dynamic_cost_function_to_functor.h b/include/ceres/dynamic_cost_function_to_functor.h
index 331d367..bc2fd3b 100644
--- a/include/ceres/dynamic_cost_function_to_functor.h
+++ b/include/ceres/dynamic_cost_function_to_functor.h
@@ -36,11 +36,11 @@
 #include <numeric>
 #include <vector>
 
+#include "absl/container/fixed_array.h"
 #include "absl/log/check.h"
 #include "ceres/dynamic_cost_function.h"
 #include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/export.h"
-#include "ceres/internal/fixed_array.h"
 
 namespace ceres {
 
@@ -130,11 +130,11 @@
     const int num_parameters = std::accumulate(
         parameter_block_sizes.begin(), parameter_block_sizes.end(), 0);
 
-    internal::FixedArray<double> parameters(num_parameters);
-    internal::FixedArray<double*> parameter_blocks(num_parameter_blocks);
-    internal::FixedArray<double> jacobians(num_residuals * num_parameters);
-    internal::FixedArray<double*> jacobian_blocks(num_parameter_blocks);
-    internal::FixedArray<double> residuals(num_residuals);
+    absl::FixedArray<double> parameters(num_parameters);
+    absl::FixedArray<double*> parameter_blocks(num_parameter_blocks);
+    absl::FixedArray<double> jacobians(num_residuals * num_parameters);
+    absl::FixedArray<double*> jacobian_blocks(num_parameter_blocks);
+    absl::FixedArray<double> residuals(num_residuals);
 
     // Build a set of arrays to get the residuals and jacobians from
     // the CostFunction wrapped by this functor.
diff --git a/include/ceres/gradient_checker.h b/include/ceres/gradient_checker.h
index 765d53c..7490cd6 100644
--- a/include/ceres/gradient_checker.h
+++ b/include/ceres/gradient_checker.h
@@ -43,7 +43,6 @@
 #include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/internal/export.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/manifold.h"
 
 namespace ceres {
diff --git a/include/ceres/internal/array_selector.h b/include/ceres/internal/array_selector.h
index 9480146..100b80d 100644
--- a/include/ceres/internal/array_selector.h
+++ b/include/ceres/internal/array_selector.h
@@ -35,7 +35,8 @@
 #include <array>
 #include <vector>
 
-#include "ceres/internal/fixed_array.h"
+#include "absl/container/fixed_array.h"
+#include "absl/log/check.h"
 #include "ceres/types.h"
 
 namespace ceres::internal {
@@ -47,7 +48,7 @@
 // Three different containers are selected in different scenarios:
 //
 //   num_elements == DYNAMIC:
-//      -> ceres::internal::FixedArray<T, max_stack_size>(size)
+//      -> absl::FixedArray<T, max_stack_size>(size)
 
 //   num_elements != DYNAMIC  &&  num_elements <= max_stack_size
 //      -> std::array<T,num_elements>
@@ -71,9 +72,9 @@
                      max_num_elements_on_stack,
                      true,
                      fits_on_stack>
-    : ceres::internal::FixedArray<T, max_num_elements_on_stack> {
+    : absl::FixedArray<T, max_num_elements_on_stack> {
   explicit ArraySelector(int s)
-      : ceres::internal::FixedArray<T, max_num_elements_on_stack>(s) {}
+      : absl::FixedArray<T, max_num_elements_on_stack>(s) {}
 };
 
 template <typename T, int num_elements, int max_num_elements_on_stack>
diff --git a/include/ceres/internal/fixed_array.h b/include/ceres/internal/fixed_array.h
deleted file mode 100644
index 68193c9..0000000
--- a/include/ceres/internal/fixed_array.h
+++ /dev/null
@@ -1,467 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// -----------------------------------------------------------------------------
-// File: fixed_array.h
-// -----------------------------------------------------------------------------
-//
-// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
-// the array can be determined at run-time. It is a good replacement for
-// non-standard and deprecated uses of `alloca()` and variable length arrays
-// within the GCC extension. (See
-// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
-//
-// `FixedArray` allocates small arrays inline, keeping performance fast by
-// avoiding heap operations. It also helps reduce the chances of
-// accidentally overflowing your stack if large input is passed to
-// your function.
-
-#ifndef CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
-#define CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
-
-#include <Eigen/Core>  // For Eigen::aligned_allocator
-#include <algorithm>
-#include <cstddef>
-#include <initializer_list>
-#include <iterator>
-#include <limits>
-#include <memory>
-#include <tuple>
-#include <type_traits>
-
-#include "absl/log/check.h"
-#include "ceres/internal/memory.h"
-
-namespace ceres::internal {
-
-constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
-
-// The default fixed array allocator.
-//
-// As one can not easily detect if a struct contains or inherits from a fixed
-// size Eigen type, to be safe the Eigen::aligned_allocator is used by default.
-// But trivial types can never contain Eigen types, so std::allocator is used to
-// safe some heap memory.
-template <typename T>
-using FixedArrayDefaultAllocator =
-    typename std::conditional<std::is_trivial<T>::value,
-                              std::allocator<T>,
-                              Eigen::aligned_allocator<T>>::type;
-
-// -----------------------------------------------------------------------------
-// FixedArray
-// -----------------------------------------------------------------------------
-//
-// A `FixedArray` provides a run-time fixed-size array, allocating a small array
-// inline for efficiency.
-//
-// Most users should not specify an `inline_elements` argument and let
-// `FixedArray` automatically determine the number of elements
-// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the
-// `FixedArray` implementation will use inline storage for arrays with a
-// length <= `inline_elements`.
-//
-// Note that a `FixedArray` constructed with a `size_type` argument will
-// default-initialize its values by leaving trivially constructible types
-// uninitialized (e.g. int, int[4], double), and others default-constructed.
-// This matches the behavior of c-style arrays and `std::array`, but not
-// `std::vector`.
-//
-// Note that `FixedArray` does not provide a public allocator; if it requires a
-// heap allocation, it will do so with global `::operator new[]()` and
-// `::operator delete[]()`, even if T provides class-scope overrides for these
-// operators.
-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>;
-  // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
-  // but this seems to be mostly pedantic.
-  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) {}
-
-  // Creates an array object that can store `n` elements.
-  // Note that trivially constructible elements will be uninitialized.
-  explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
-      : storage_(n, a) {
-    if (DefaultConstructorIsNonTrivial()) {
-      ConstructRange(storage_.alloc(), storage_.begin(), storage_.end());
-    }
-  }
-
-  // Creates an array initialized with `n` copies of `val`.
-  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);
-  }
-
-  // Creates an array initialized with the size and contents of `init_list`.
-  FixedArray(std::initializer_list<value_type> init_list,
-             const allocator_type& a = allocator_type())
-      : FixedArray(init_list.begin(), init_list.end(), a) {}
-
-  // Creates an array initialized with the elements from the input
-  // range. The array's size will always be `std::distance(first, last)`.
-  // REQUIRES: Iterator must be a forward_iterator or better.
-  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);
-    }
-  }
-
-  // Assignments are deleted because they break the invariant that the size of a
-  // `FixedArray` never changes.
-  void operator=(FixedArray&&) = delete;
-  void operator=(const FixedArray&) = delete;
-
-  // FixedArray::size()
-  //
-  // Returns the length of the fixed array.
-  size_type size() const { return storage_.size(); }
-
-  // FixedArray::max_size()
-  //
-  // Returns the largest possible value of `std::distance(begin(), end())` for a
-  // `FixedArray<T>`. This is equivalent to the most possible addressable bytes
-  // over the number of bytes taken by T.
-  constexpr size_type max_size() const {
-    return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
-  }
-
-  // FixedArray::empty()
-  //
-  // Returns whether or not the fixed array is empty.
-  bool empty() const { return size() == 0; }
-
-  // FixedArray::memsize()
-  //
-  // Returns the memory size of the fixed array in bytes.
-  size_t memsize() const { return size() * sizeof(value_type); }
-
-  // FixedArray::data()
-  //
-  // Returns a const T* pointer to elements of the `FixedArray`. This pointer
-  // can be used to access (but not modify) the contained elements.
-  const_pointer data() const { return AsValueType(storage_.begin()); }
-
-  // Overload of FixedArray::data() to return a T* pointer to elements of the
-  // fixed array. This pointer can be used to access and modify the contained
-  // elements.
-  pointer data() { return AsValueType(storage_.begin()); }
-
-  // FixedArray::operator[]
-  //
-  // Returns a reference the ith element of the fixed array.
-  // REQUIRES: 0 <= i < size()
-  reference operator[](size_type i) {
-    DCHECK_LT(i, size());
-    return data()[i];
-  }
-
-  // Overload of FixedArray::operator()[] to return a const reference to the
-  // ith element of the fixed array.
-  // REQUIRES: 0 <= i < size()
-  const_reference operator[](size_type i) const {
-    DCHECK_LT(i, size());
-    return data()[i];
-  }
-
-  // FixedArray::front()
-  //
-  // Returns a reference to the first element of the fixed array.
-  reference front() { return *begin(); }
-
-  // Overload of FixedArray::front() to return a reference to the first element
-  // of a fixed array of const values.
-  const_reference front() const { return *begin(); }
-
-  // FixedArray::back()
-  //
-  // Returns a reference to the last element of the fixed array.
-  reference back() { return *(end() - 1); }
-
-  // Overload of FixedArray::back() to return a reference to the last element
-  // of a fixed array of const values.
-  const_reference back() const { return *(end() - 1); }
-
-  // FixedArray::begin()
-  //
-  // Returns an iterator to the beginning of the fixed array.
-  iterator begin() { return data(); }
-
-  // Overload of FixedArray::begin() to return a const iterator to the
-  // beginning of the fixed array.
-  const_iterator begin() const { return data(); }
-
-  // FixedArray::cbegin()
-  //
-  // Returns a const iterator to the beginning of the fixed array.
-  const_iterator cbegin() const { return begin(); }
-
-  // FixedArray::end()
-  //
-  // Returns an iterator to the end of the fixed array.
-  iterator end() { return data() + size(); }
-
-  // Overload of FixedArray::end() to return a const iterator to the end of the
-  // fixed array.
-  const_iterator end() const { return data() + size(); }
-
-  // FixedArray::cend()
-  //
-  // Returns a const iterator to the end of the fixed array.
-  const_iterator cend() const { return end(); }
-
-  // FixedArray::rbegin()
-  //
-  // Returns a reverse iterator from the end of the fixed array.
-  reverse_iterator rbegin() { return reverse_iterator(end()); }
-
-  // Overload of FixedArray::rbegin() to return a const reverse iterator from
-  // the end of the fixed array.
-  const_reverse_iterator rbegin() const {
-    return const_reverse_iterator(end());
-  }
-
-  // FixedArray::crbegin()
-  //
-  // Returns a const reverse iterator from the end of the fixed array.
-  const_reverse_iterator crbegin() const { return rbegin(); }
-
-  // FixedArray::rend()
-  //
-  // Returns a reverse iterator from the beginning of the fixed array.
-  reverse_iterator rend() { return reverse_iterator(begin()); }
-
-  // Overload of FixedArray::rend() for returning a const reverse iterator
-  // from the beginning of the fixed array.
-  const_reverse_iterator rend() const {
-    return const_reverse_iterator(begin());
-  }
-
-  // FixedArray::crend()
-  //
-  // Returns a reverse iterator from the beginning of the fixed array.
-  const_reverse_iterator crend() const { return rend(); }
-
-  // FixedArray::fill()
-  //
-  // Assigns the given `value` to all elements in the fixed array.
-  void fill(const value_type& val) { std::fill(begin(), end(), val); }
-
-  // Relational operators. Equality operators are elementwise using
-  // `operator==`, while order operators order FixedArrays lexicographically.
-  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:
-  // StorageElement
-  //
-  // For FixedArrays with a C-style-array value_type, StorageElement is a POD
-  // wrapper struct called StorageElementWrapper that holds the value_type
-  // instance inside. This is needed for construction and destruction of the
-  // entire array regardless of how many dimensions it has. For all other cases,
-  // StorageElement is just an alias of value_type.
-  //
-  // Maintainer's Note: The simpler solution would be to simply wrap value_type
-  // in a struct whether it's an array or not. That causes some paranoid
-  // diagnostics to misfire, believing that 'data()' returns a pointer to a
-  // single element, rather than the packed array that it really is.
-  // e.g.:
-  //
-  //     FixedArray<char> buf(1);
-  //     sprintf(buf.data(), "foo");
-  //
-  //     error: call to int __builtin___sprintf_chk(etc...)
-  //     will always overflow destination buffer [-Werror]
-  //
-  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) {}
-
-    // #ifdef ADDRESS_SANITIZER
-    //     void* RedzoneBegin() { return &redzone_begin_; }
-    //     void* RedzoneEnd() { return &redzone_end_ + 1; }
-    // #endif  // ADDRESS_SANITIZER
-
-   private:
-    // ADDRESS_SANITIZER_REDZONE(redzone_begin_);
-    alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
-    // ADDRESS_SANITIZER_REDZONE(redzone_end_);
-  };
-
-  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;
-
-  // Storage
-  //
-  // An instance of Storage manages the inline and out-of-line memory for
-  // instances of FixedArray. This guarantees that even when construction of
-  // individual elements fails in the FixedArray constructor body, the
-  // destructor for Storage will still be called and out-of-line memory will be
-  // properly deallocated.
-  //
-  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()));
-      }
-    }
-
-    // Using std::tuple and not absl::CompressedTuple, as it has a lot of
-    // dependencies to other absl headers.
-    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;
-
-}  // namespace ceres::internal
-
-#endif  // CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
diff --git a/include/ceres/internal/numeric_diff.h b/include/ceres/internal/numeric_diff.h
index 4031631..976b27f 100644
--- a/include/ceres/internal/numeric_diff.h
+++ b/include/ceres/internal/numeric_diff.h
@@ -40,9 +40,9 @@
 
 #include "Eigen/Dense"
 #include "Eigen/StdVector"
+#include "absl/container/fixed_array.h"
 #include "absl/log/check.h"
 #include "ceres/cost_function.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/internal/variadic_evaluate.h"
 #include "ceres/numeric_diff_options.h"
 #include "ceres/types.h"
@@ -125,8 +125,8 @@
 
     // For each parameter in the parameter block, use finite differences to
     // compute the derivative for that parameter.
-    FixedArray<double> temp_residual_array(num_residuals_internal);
-    FixedArray<double> residual_array(num_residuals_internal);
+    absl::FixedArray<double> temp_residual_array(num_residuals_internal);
+    absl::FixedArray<double> residual_array(num_residuals_internal);
     Map<ResidualVector> residuals(residual_array.data(),
                                   num_residuals_internal);
 
diff --git a/include/ceres/numeric_diff_cost_function.h b/include/ceres/numeric_diff_cost_function.h
index f2a377b..47e4af4 100644
--- a/include/ceres/numeric_diff_cost_function.h
+++ b/include/ceres/numeric_diff_cost_function.h
@@ -228,7 +228,7 @@
   bool Evaluate(double const* const* parameters,
                 double* residuals,
                 double** jacobians) const override {
-    using internal::FixedArray;
+    using absl::FixedArray;
     using internal::NumericDiff;
 
     using ParameterDims =
diff --git a/include/ceres/numeric_diff_first_order_function.h b/include/ceres/numeric_diff_first_order_function.h
index 790cbcd..a9a7798 100644
--- a/include/ceres/numeric_diff_first_order_function.h
+++ b/include/ceres/numeric_diff_first_order_function.h
@@ -36,10 +36,10 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/container/fixed_array.h"
 #include "absl/log/check.h"
 #include "ceres/first_order_function.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/internal/numeric_diff.h"
 #include "ceres/internal/parameter_dims.h"
 #include "ceres/internal/variadic_evaluate.h"
@@ -197,7 +197,7 @@
     }
 
     // Create a copy of the parameters which will get mutated.
-    internal::FixedArray<double, 32> parameters_copy(num_parameters_);
+    absl::FixedArray<double> parameters_copy(num_parameters_);
     std::copy_n(parameters, num_parameters_, parameters_copy.data());
     double* parameters_ptr = parameters_copy.data();
     constexpr int kNumResiduals = 1;
diff --git a/include/ceres/product_manifold.h b/include/ceres/product_manifold.h
index ed2d1f4..9fc836e 100644
--- a/include/ceres/product_manifold.h
+++ b/include/ceres/product_manifold.h
@@ -42,8 +42,8 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/container/fixed_array.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/internal/port.h"
 #include "ceres/manifold.h"
 
@@ -117,7 +117,7 @@
   bool PlusJacobian(const double* x, double* jacobian_ptr) const override {
     MatrixRef jacobian(jacobian_ptr, AmbientSize(), TangentSize());
     jacobian.setZero();
-    internal::FixedArray<double> buffer(buffer_size_);
+    absl::FixedArray<double> buffer(buffer_size_);
 
     return PlusJacobianImpl(
         x, jacobian, buffer, std::make_index_sequence<kNumManifolds>{});
@@ -126,7 +126,7 @@
   bool MinusJacobian(const double* x, double* jacobian_ptr) const override {
     MatrixRef jacobian(jacobian_ptr, TangentSize(), AmbientSize());
     jacobian.setZero();
-    internal::FixedArray<double> buffer(buffer_size_);
+    absl::FixedArray<double> buffer(buffer_size_);
 
     return MinusJacobianImpl(
         x, jacobian, buffer, std::make_index_sequence<kNumManifolds>{});
@@ -199,7 +199,7 @@
   template <std::size_t Index0, std::size_t... Indices>
   bool PlusJacobianImpl(const double* x,
                         MatrixRef& jacobian,
-                        internal::FixedArray<double>& buffer,
+                        absl::FixedArray<double>& buffer,
                         std::index_sequence<Index0, Indices...>) const {
     if (!Dereference(std::get<Index0>(manifolds_))
              .PlusJacobian(x + ambient_offsets_[Index0], buffer.data())) {
@@ -217,18 +217,17 @@
         x, jacobian, buffer, std::index_sequence<Indices...>{});
   }
 
-  static constexpr bool PlusJacobianImpl(
-      const double* /*x*/,
-      MatrixRef& /*jacobian*/,
-      internal::FixedArray<double>& /*buffer*/,
-      std::index_sequence<>) noexcept {
+  static constexpr bool PlusJacobianImpl(const double* /*x*/,
+                                         MatrixRef& /*jacobian*/,
+                                         absl::FixedArray<double>& /*buffer*/,
+                                         std::index_sequence<>) noexcept {
     return true;
   }
 
   template <std::size_t Index0, std::size_t... Indices>
   bool MinusJacobianImpl(const double* x,
                          MatrixRef& jacobian,
-                         internal::FixedArray<double>& buffer,
+                         absl::FixedArray<double>& buffer,
                          std::index_sequence<Index0, Indices...>) const {
     if (!Dereference(std::get<Index0>(manifolds_))
              .MinusJacobian(x + ambient_offsets_[Index0], buffer.data())) {
@@ -246,11 +245,10 @@
         x, jacobian, buffer, std::index_sequence<Indices...>{});
   }
 
-  static constexpr bool MinusJacobianImpl(
-      const double* /*x*/,
-      MatrixRef& /*jacobian*/,
-      internal::FixedArray<double>& /*buffer*/,
-      std::index_sequence<>) noexcept {
+  static constexpr bool MinusJacobianImpl(const double* /*x*/,
+                                          MatrixRef& /*jacobian*/,
+                                          absl::FixedArray<double>& /*buffer*/,
+                                          std::index_sequence<>) noexcept {
     return true;
   }
 
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index f30ba00..808e0ed 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -39,6 +39,7 @@
 
 list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES absl::log)
 list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES absl::check)
+list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES absl::fixed_array)
 
 # Source files that contain public symbols and live in the ceres namespaces.
 # Such symbols are expected to be marked with CERES_EXPORT and the files below
@@ -450,7 +451,6 @@
   ceres_test(dynamic_sparsity)
   ceres_test(evaluation_callback)
   ceres_test(evaluator)
-  ceres_test(fixed_array)
   ceres_test(gradient_checker)
   ceres_test(gradient_checking_cost_function)
   ceres_test(gradient_problem)
diff --git a/internal/ceres/array_selector_test.cc b/internal/ceres/array_selector_test.cc
index 36155f1..0b6c893 100644
--- a/internal/ceres/array_selector_test.cc
+++ b/internal/ceres/array_selector_test.cc
@@ -35,7 +35,7 @@
 #include <type_traits>
 #include <vector>
 
-#include "ceres/internal/fixed_array.h"
+#include "absl/container/fixed_array.h"
 #include "ceres/types.h"
 #include "gtest/gtest.h"
 
@@ -47,12 +47,12 @@
 TEST(ArraySelector, FixedArray) {
   ArraySelector<int, DYNAMIC, 20> array1(10);
   static_assert(
-      std::is_base_of<internal::FixedArray<int, 20>, decltype(array1)>::value);
+      std::is_base_of<absl::FixedArray<int, 20>, decltype(array1)>::value);
   EXPECT_EQ(array1.size(), 10);
 
   ArraySelector<int, DYNAMIC, 10> array2(20);
   static_assert(
-      std::is_base_of<internal::FixedArray<int, 10>, decltype(array2)>::value);
+      std::is_base_of<absl::FixedArray<int, 10>, decltype(array2)>::value);
   EXPECT_EQ(array2.size(), 20);
 }
 
diff --git a/internal/ceres/autodiff_test.cc b/internal/ceres/autodiff_test.cc
index b50327c..787adf8 100644
--- a/internal/ceres/autodiff_test.cc
+++ b/internal/ceres/autodiff_test.cc
@@ -34,6 +34,7 @@
 #include <iterator>
 #include <random>
 
+#include "absl/container/fixed_array.h"
 #include "gtest/gtest.h"
 
 namespace ceres::internal {
@@ -666,7 +667,7 @@
   y += 1;
 
   using JetT = Jet<double, 2>;
-  FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(3);
+  absl::FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(3);
 
   // Need this to makes sure that x does not get optimized out.
   x[0] = x[0] + JetT(1.0);
diff --git a/internal/ceres/eigen_vector_ops.h b/internal/ceres/eigen_vector_ops.h
index 6ebff88..cc0a59b 100644
--- a/internal/ceres/eigen_vector_ops.h
+++ b/internal/ceres/eigen_vector_ops.h
@@ -33,8 +33,8 @@
 
 #include <numeric>
 
+#include "absl/container/fixed_array.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/parallel_for.h"
 #include "ceres/parallel_vector_ops.h"
 
@@ -47,7 +47,7 @@
 inline double Norm(const Eigen::DenseBase<Derived>& x,
                    ContextImpl* context,
                    int num_threads) {
-  FixedArray<double> norms(num_threads, 0.);
+  absl::FixedArray<double> norms(num_threads, 0.);
   ParallelFor(
       context,
       0,
@@ -77,7 +77,7 @@
                   const VectorLikeY& y,
                   ContextImpl* context,
                   int num_threads) {
-  FixedArray<double> dots(num_threads, 0.);
+  absl::FixedArray<double> dots(num_threads, 0.);
   ParallelFor(
       context,
       0,
diff --git a/internal/ceres/fixed_array_test.cc b/internal/ceres/fixed_array_test.cc
deleted file mode 100644
index 66b3fbf..0000000
--- a/internal/ceres/fixed_array_test.cc
+++ /dev/null
@@ -1,835 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "ceres/internal/fixed_array.h"
-
-#include <cstdio>
-#include <cstring>
-#include <list>
-#include <memory>
-#include <numeric>
-#include <scoped_allocator>
-#include <stdexcept>
-#include <string>
-#include <vector>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using ::testing::ElementsAreArray;
-
-namespace {
-
-// CERES_INTERNAL_ARRAYSIZE()
-//
-// Returns the number of elements in an array as a compile-time constant, which
-// can be used in defining new arrays. If you use this macro on a pointer by
-// mistake, you will get a compile-time error.
-#define CERES_INTERNAL_ARRAYSIZE(array) (sizeof(ArraySizeHelper(array)))
-
-// Note: this internal template function declaration is used by
-// CERES_INTERNAL_ARRAYSIZE. The function doesn't need a definition, as we only
-// use its type.
-template <typename T, size_t N>
-auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
-
-// Helper routine to determine if a ceres::internal::FixedArray used stack
-// allocation.
-template <typename ArrayType>
-static bool IsOnStack(const ArrayType& a) {
-  return a.size() <= ArrayType::inline_elements;
-}
-
-class ConstructionTester {
- public:
-  ConstructionTester() : self_ptr_(this) { constructions++; }
-  ~ConstructionTester() {
-    assert(self_ptr_ == this);
-    self_ptr_ = nullptr;
-    destructions++;
-  }
-
-  // These are incremented as elements are constructed and destructed so we can
-  // be sure all elements are properly cleaned up.
-  static int constructions;
-  static int destructions;
-
-  void CheckConstructed() { assert(self_ptr_ == this); }
-
-  void set(int value) { value_ = value; }
-  int get() { return value_; }
-
- private:
-  // self_ptr_ should always point to 'this' -- that's how we can be sure the
-  // constructor has been called.
-  ConstructionTester* self_ptr_;
-  int value_{0};
-};
-
-int ConstructionTester::constructions = 0;
-int ConstructionTester::destructions = 0;
-
-// ThreeInts will initialize its three ints to the value stored in
-// ThreeInts::counter. The constructor increments counter so that each object
-// in an array of ThreeInts will have different values.
-class ThreeInts {
- public:
-  ThreeInts() {
-    x_ = counter;
-    y_ = counter;
-    z_ = counter;
-    ++counter;
-  }
-
-  static int counter;
-
-  int x_, y_, z_;
-};
-
-int ThreeInts::counter = 0;
-
-TEST(FixedArrayTest, CopyCtor) {
-  ceres::internal::FixedArray<int, 10> on_stack(5);
-  std::iota(on_stack.begin(), on_stack.end(), 0);
-  ceres::internal::FixedArray<int, 10> stack_copy = on_stack;
-  EXPECT_THAT(stack_copy, ElementsAreArray(on_stack));
-  EXPECT_TRUE(IsOnStack(stack_copy));
-
-  ceres::internal::FixedArray<int, 10> allocated(15);
-  std::iota(allocated.begin(), allocated.end(), 0);
-  ceres::internal::FixedArray<int, 10> alloced_copy = allocated;
-  EXPECT_THAT(alloced_copy, ElementsAreArray(allocated));
-  EXPECT_FALSE(IsOnStack(alloced_copy));
-}
-
-TEST(FixedArrayTest, MoveCtor) {
-  ceres::internal::FixedArray<std::unique_ptr<int>, 10> on_stack(5);
-  for (int i = 0; i < 5; ++i) {
-    on_stack[i] = std::make_unique<int>(i);
-  }
-
-  ceres::internal::FixedArray<std::unique_ptr<int>, 10> stack_copy =
-      std::move(on_stack);
-  for (int i = 0; i < 5; ++i) EXPECT_EQ(*(stack_copy[i]), i);
-  EXPECT_EQ(stack_copy.size(), on_stack.size());
-
-  ceres::internal::FixedArray<std::unique_ptr<int>, 10> allocated(15);
-  for (int i = 0; i < 15; ++i) {
-    allocated[i] = std::make_unique<int>(i);
-  }
-
-  ceres::internal::FixedArray<std::unique_ptr<int>, 10> alloced_copy =
-      std::move(allocated);
-  for (int i = 0; i < 15; ++i) EXPECT_EQ(*(alloced_copy[i]), i);
-  EXPECT_EQ(allocated.size(), alloced_copy.size());
-}
-
-TEST(FixedArrayTest, SmallObjects) {
-  // Small object arrays
-  {
-    // Short arrays should be on the stack
-    ceres::internal::FixedArray<int> array(4);
-    EXPECT_TRUE(IsOnStack(array));
-  }
-
-  {
-    // Large arrays should be on the heap
-    ceres::internal::FixedArray<int> array(1048576);
-    EXPECT_FALSE(IsOnStack(array));
-  }
-
-  {
-    // Arrays of <= default size should be on the stack
-    ceres::internal::FixedArray<int, 100> array(100);
-    EXPECT_TRUE(IsOnStack(array));
-  }
-
-  {
-    // Arrays of > default size should be on the heap
-    ceres::internal::FixedArray<int, 100> array(101);
-    EXPECT_FALSE(IsOnStack(array));
-  }
-
-  {
-    // Arrays with different size elements should use approximately
-    // same amount of stack space
-    ceres::internal::FixedArray<int> array1(0);
-    ceres::internal::FixedArray<char> array2(0);
-    EXPECT_LE(sizeof(array1), sizeof(array2) + 100);
-    EXPECT_LE(sizeof(array2), sizeof(array1) + 100);
-  }
-
-  {
-    // Ensure that vectors are properly constructed inside a fixed array.
-    ceres::internal::FixedArray<std::vector<int>> array(2);
-    EXPECT_EQ(0, array[0].size());
-    EXPECT_EQ(0, array[1].size());
-  }
-
-  {
-    // Regardless of ceres::internal::FixedArray implementation, check that a
-    // type with a low alignment requirement and a non power-of-two size is
-    // initialized correctly.
-    ThreeInts::counter = 1;
-    ceres::internal::FixedArray<ThreeInts> array(2);
-    EXPECT_EQ(1, array[0].x_);
-    EXPECT_EQ(1, array[0].y_);
-    EXPECT_EQ(1, array[0].z_);
-    EXPECT_EQ(2, array[1].x_);
-    EXPECT_EQ(2, array[1].y_);
-    EXPECT_EQ(2, array[1].z_);
-  }
-}
-
-TEST(FixedArrayRelationalsTest, EqualArrays) {
-  for (int i = 0; i < 10; ++i) {
-    ceres::internal::FixedArray<int, 5> a1(i);
-    std::iota(a1.begin(), a1.end(), 0);
-    ceres::internal::FixedArray<int, 5> a2(a1.begin(), a1.end());
-
-    EXPECT_TRUE(a1 == a2);
-    EXPECT_FALSE(a1 != a2);
-    EXPECT_TRUE(a2 == a1);
-    EXPECT_FALSE(a2 != a1);
-    EXPECT_FALSE(a1 < a2);
-    EXPECT_FALSE(a1 > a2);
-    EXPECT_FALSE(a2 < a1);
-    EXPECT_FALSE(a2 > a1);
-    EXPECT_TRUE(a1 <= a2);
-    EXPECT_TRUE(a1 >= a2);
-    EXPECT_TRUE(a2 <= a1);
-    EXPECT_TRUE(a2 >= a1);
-  }
-}
-
-TEST(FixedArrayRelationalsTest, UnequalArrays) {
-  for (int i = 1; i < 10; ++i) {
-    ceres::internal::FixedArray<int, 5> a1(i);
-    std::iota(a1.begin(), a1.end(), 0);
-    ceres::internal::FixedArray<int, 5> a2(a1.begin(), a1.end());
-    --a2[i / 2];
-
-    EXPECT_FALSE(a1 == a2);
-    EXPECT_TRUE(a1 != a2);
-    EXPECT_FALSE(a2 == a1);
-    EXPECT_TRUE(a2 != a1);
-    EXPECT_FALSE(a1 < a2);
-    EXPECT_TRUE(a1 > a2);
-    EXPECT_TRUE(a2 < a1);
-    EXPECT_FALSE(a2 > a1);
-    EXPECT_FALSE(a1 <= a2);
-    EXPECT_TRUE(a1 >= a2);
-    EXPECT_TRUE(a2 <= a1);
-    EXPECT_FALSE(a2 >= a1);
-  }
-}
-
-template <int stack_elements>
-static void TestArray(int n) {
-  SCOPED_TRACE(n);
-  SCOPED_TRACE(stack_elements);
-  ConstructionTester::constructions = 0;
-  ConstructionTester::destructions = 0;
-  {
-    ceres::internal::FixedArray<ConstructionTester, stack_elements> array(n);
-
-    EXPECT_THAT(array.size(), n);
-    EXPECT_THAT(array.memsize(), sizeof(ConstructionTester) * n);
-    EXPECT_THAT(array.begin() + n, array.end());
-
-    // Check that all elements were constructed
-    for (int i = 0; i < n; i++) {
-      array[i].CheckConstructed();
-    }
-    // Check that no other elements were constructed
-    EXPECT_THAT(ConstructionTester::constructions, n);
-
-    // Test operator[]
-    for (int i = 0; i < n; i++) {
-      array[i].set(i);
-    }
-    for (int i = 0; i < n; i++) {
-      EXPECT_THAT(array[i].get(), i);
-      EXPECT_THAT(array.data()[i].get(), i);
-    }
-
-    // Test data()
-    for (int i = 0; i < n; i++) {
-      array.data()[i].set(i + 1);
-    }
-    for (int i = 0; i < n; i++) {
-      EXPECT_THAT(array[i].get(), i + 1);
-      EXPECT_THAT(array.data()[i].get(), i + 1);
-    }
-  }  // Close scope containing 'array'.
-
-  // Check that all constructed elements were destructed.
-  EXPECT_EQ(ConstructionTester::constructions,
-            ConstructionTester::destructions);
-}
-
-template <int elements_per_inner_array, int inline_elements>
-static void TestArrayOfArrays(int n) {
-  SCOPED_TRACE(n);
-  SCOPED_TRACE(inline_elements);
-  SCOPED_TRACE(elements_per_inner_array);
-  ConstructionTester::constructions = 0;
-  ConstructionTester::destructions = 0;
-  {
-    using InnerArray = ConstructionTester[elements_per_inner_array];
-    // Heap-allocate the FixedArray to avoid blowing the stack frame.
-    auto array_ptr = std::unique_ptr<
-        ceres::internal::FixedArray<InnerArray, inline_elements>>(
-        new ceres::internal::FixedArray<InnerArray, inline_elements>(n));
-    auto& array = *array_ptr;
-
-    ASSERT_EQ(array.size(), n);
-    ASSERT_EQ(array.memsize(),
-              sizeof(ConstructionTester) * elements_per_inner_array * n);
-    ASSERT_EQ(array.begin() + n, array.end());
-
-    // Check that all elements were constructed
-    for (int i = 0; i < n; i++) {
-      for (int j = 0; j < elements_per_inner_array; j++) {
-        (array[i])[j].CheckConstructed();
-      }
-    }
-    // Check that no other elements were constructed
-    ASSERT_EQ(ConstructionTester::constructions, n * elements_per_inner_array);
-
-    // Test operator[]
-    for (int i = 0; i < n; i++) {
-      for (int j = 0; j < elements_per_inner_array; j++) {
-        (array[i])[j].set(i * elements_per_inner_array + j);
-      }
-    }
-    for (int i = 0; i < n; i++) {
-      for (int j = 0; j < elements_per_inner_array; j++) {
-        ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j);
-        ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j);
-      }
-    }
-
-    // Test data()
-    for (int i = 0; i < n; i++) {
-      for (int j = 0; j < elements_per_inner_array; j++) {
-        (array.data()[i])[j].set((i + 1) * elements_per_inner_array + j);
-      }
-    }
-    for (int i = 0; i < n; i++) {
-      for (int j = 0; j < elements_per_inner_array; j++) {
-        ASSERT_EQ((array[i])[j].get(), (i + 1) * elements_per_inner_array + j);
-        ASSERT_EQ((array.data()[i])[j].get(),
-                  (i + 1) * elements_per_inner_array + j);
-      }
-    }
-  }  // Close scope containing 'array'.
-
-  // Check that all constructed elements were destructed.
-  EXPECT_EQ(ConstructionTester::constructions,
-            ConstructionTester::destructions);
-}
-
-TEST(IteratorConstructorTest, NonInline) {
-  int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
-  ceres::internal::FixedArray<int, CERES_INTERNAL_ARRAYSIZE(kInput) - 1> const
-      fixed(kInput, kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
-  ASSERT_EQ(CERES_INTERNAL_ARRAYSIZE(kInput), fixed.size());
-  for (size_t i = 0; i < CERES_INTERNAL_ARRAYSIZE(kInput); ++i) {
-    ASSERT_EQ(kInput[i], fixed[i]);
-  }
-}
-
-TEST(IteratorConstructorTest, Inline) {
-  int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
-  ceres::internal::FixedArray<int, CERES_INTERNAL_ARRAYSIZE(kInput)> const
-      fixed(kInput, kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
-  ASSERT_EQ(CERES_INTERNAL_ARRAYSIZE(kInput), fixed.size());
-  for (size_t i = 0; i < CERES_INTERNAL_ARRAYSIZE(kInput); ++i) {
-    ASSERT_EQ(kInput[i], fixed[i]);
-  }
-}
-
-TEST(IteratorConstructorTest, NonPod) {
-  char const* kInput[] = {
-      "red", "orange", "yellow", "green", "blue", "indigo", "violet"};
-  ceres::internal::FixedArray<std::string> const fixed(
-      kInput, kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
-  ASSERT_EQ(CERES_INTERNAL_ARRAYSIZE(kInput), fixed.size());
-  for (size_t i = 0; i < CERES_INTERNAL_ARRAYSIZE(kInput); ++i) {
-    ASSERT_EQ(kInput[i], fixed[i]);
-  }
-}
-
-TEST(IteratorConstructorTest, FromEmptyVector) {
-  std::vector<int> const empty;
-  ceres::internal::FixedArray<int> const fixed(empty.begin(), empty.end());
-  EXPECT_EQ(0, fixed.size());
-  EXPECT_EQ(empty.size(), fixed.size());
-}
-
-TEST(IteratorConstructorTest, FromNonEmptyVector) {
-  int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
-  std::vector<int> const items(kInput,
-                               kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
-  ceres::internal::FixedArray<int> const fixed(items.begin(), items.end());
-  ASSERT_EQ(items.size(), fixed.size());
-  for (size_t i = 0; i < items.size(); ++i) {
-    ASSERT_EQ(items[i], fixed[i]);
-  }
-}
-
-TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) {
-  int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
-  std::list<int> const items(kInput, kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
-  ceres::internal::FixedArray<int> const fixed(items.begin(), items.end());
-  EXPECT_THAT(fixed, testing::ElementsAreArray(kInput));
-}
-
-TEST(InitListConstructorTest, InitListConstruction) {
-  ceres::internal::FixedArray<int> fixed = {1, 2, 3};
-  EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3}));
-}
-
-TEST(FillConstructorTest, NonEmptyArrays) {
-  ceres::internal::FixedArray<int> stack_array(4, 1);
-  EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
-
-  ceres::internal::FixedArray<int, 0> heap_array(4, 1);
-  EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
-}
-
-TEST(FillConstructorTest, EmptyArray) {
-  ceres::internal::FixedArray<int> empty_fill(0, 1);
-  ceres::internal::FixedArray<int> empty_size(0);
-  EXPECT_EQ(empty_fill, empty_size);
-}
-
-TEST(FillConstructorTest, NotTriviallyCopyable) {
-  std::string str = "abcd";
-  ceres::internal::FixedArray<std::string> strings = {str, str, str, str};
-
-  ceres::internal::FixedArray<std::string> array(4, str);
-  EXPECT_EQ(array, strings);
-}
-
-TEST(FillConstructorTest, Disambiguation) {
-  ceres::internal::FixedArray<size_t> a(1, 2);
-  EXPECT_THAT(a, testing::ElementsAre(2));
-}
-
-TEST(FixedArrayTest, ManySizedArrays) {
-  std::vector<int> sizes;
-  for (int i = 1; i < 100; i++) sizes.push_back(i);
-  for (int i = 100; i <= 1000; i += 100) sizes.push_back(i);
-  for (int n : sizes) {
-    TestArray<0>(n);
-    TestArray<1>(n);
-    TestArray<64>(n);
-    TestArray<1000>(n);
-  }
-}
-
-TEST(FixedArrayTest, ManySizedArraysOfArraysOf1) {
-  for (int n = 1; n < 1000; n++) {
-    ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 0>(n)));
-    ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1>(n)));
-    ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 64>(n)));
-    ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1000>(n)));
-  }
-}
-
-TEST(FixedArrayTest, ManySizedArraysOfArraysOf2) {
-  for (int n = 1; n < 1000; n++) {
-    TestArrayOfArrays<2, 0>(n);
-    TestArrayOfArrays<2, 1>(n);
-    TestArrayOfArrays<2, 64>(n);
-    TestArrayOfArrays<2, 1000>(n);
-  }
-}
-
-// If value_type is put inside of a struct container,
-// we might evoke this error in a hardened build unless data() is carefully
-// written, so check on that.
-//     error: call to int __builtin___sprintf_chk(etc...)
-//     will always overflow destination buffer [-Werror]
-TEST(FixedArrayTest, AvoidParanoidDiagnostics) {
-  ceres::internal::FixedArray<char, 32> buf(32);
-  snprintf(buf.data(), 32, "foo");
-}
-
-TEST(FixedArrayTest, TooBigInlinedSpace) {
-  struct TooBig {
-    char c[1 << 20];
-  };  // too big for even one on the stack
-
-  // Simulate the data members of ceres::internal::FixedArray, a pointer and a
-  // size_t.
-  struct Data {
-    std::tuple<size_t, std::allocator<double>> size_alloc_;
-    TooBig* p;
-  };
-
-  // Make sure TooBig objects are not inlined for 0 or default size.
-  static_assert(
-      sizeof(ceres::internal::FixedArray<TooBig, 0>) == sizeof(Data),
-      "0-sized ceres::internal::FixedArray should have same size as Data.");
-  static_assert(
-      alignof(ceres::internal::FixedArray<TooBig, 0>) == alignof(Data),
-      "0-sized ceres::internal::FixedArray should have same alignment as "
-      "Data.");
-  static_assert(sizeof(ceres::internal::FixedArray<TooBig>) == sizeof(Data),
-                "default-sized ceres::internal::FixedArray should have same "
-                "size as Data");
-  static_assert(alignof(ceres::internal::FixedArray<TooBig>) == alignof(Data),
-                "default-sized ceres::internal::FixedArray should have same "
-                "alignment as Data.");
-}
-
-// PickyDelete EXPECTs its class-scope deallocation funcs are unused.
-struct PickyDelete {
-  void operator delete(void* p) {
-    EXPECT_TRUE(false) << __FUNCTION__;
-    ::operator delete(p);
-  }
-  void operator delete[](void* p) {
-    EXPECT_TRUE(false) << __FUNCTION__;
-    ::operator delete[](p);
-  }
-};
-
-TEST(FixedArrayTest, UsesGlobalAlloc) {
-  ceres::internal::FixedArray<PickyDelete, 0> a(5);
-}
-
-TEST(FixedArrayTest, Data) {
-  static const int kInput[] = {2, 3, 5, 7, 11, 13, 17};
-  ceres::internal::FixedArray<int> fa(std::begin(kInput), std::end(kInput));
-  EXPECT_EQ(fa.data(), &*fa.begin());
-  EXPECT_EQ(fa.data(), &fa[0]);
-
-  const ceres::internal::FixedArray<int>& cfa = fa;
-  EXPECT_EQ(cfa.data(), &*cfa.begin());
-  EXPECT_EQ(cfa.data(), &cfa[0]);
-}
-
-TEST(FixedArrayTest, Empty) {
-  ceres::internal::FixedArray<int> empty(0);
-  ceres::internal::FixedArray<int> inline_filled(1);
-  ceres::internal::FixedArray<int, 0> heap_filled(1);
-  EXPECT_TRUE(empty.empty());
-  EXPECT_FALSE(inline_filled.empty());
-  EXPECT_FALSE(heap_filled.empty());
-}
-
-TEST(FixedArrayTest, FrontAndBack) {
-  ceres::internal::FixedArray<int, 3 * sizeof(int)> inlined = {1, 2, 3};
-  EXPECT_EQ(inlined.front(), 1);
-  EXPECT_EQ(inlined.back(), 3);
-
-  ceres::internal::FixedArray<int, 0> allocated = {1, 2, 3};
-  EXPECT_EQ(allocated.front(), 1);
-  EXPECT_EQ(allocated.back(), 3);
-
-  ceres::internal::FixedArray<int> one_element = {1};
-  EXPECT_EQ(one_element.front(), one_element.back());
-}
-
-TEST(FixedArrayTest, ReverseIteratorInlined) {
-  ceres::internal::FixedArray<int, 5 * sizeof(int)> a = {0, 1, 2, 3, 4};
-
-  int counter = 5;
-  for (ceres::internal::FixedArray<int>::reverse_iterator iter = a.rbegin();
-       iter != a.rend();
-       ++iter) {
-    counter--;
-    EXPECT_EQ(counter, *iter);
-  }
-  EXPECT_EQ(counter, 0);
-
-  counter = 5;
-  for (ceres::internal::FixedArray<int>::const_reverse_iterator iter =
-           a.rbegin();
-       iter != a.rend();
-       ++iter) {
-    counter--;
-    EXPECT_EQ(counter, *iter);
-  }
-  EXPECT_EQ(counter, 0);
-
-  counter = 5;
-  for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
-    counter--;
-    EXPECT_EQ(counter, *iter);
-  }
-  EXPECT_EQ(counter, 0);
-}
-
-TEST(FixedArrayTest, ReverseIteratorAllocated) {
-  ceres::internal::FixedArray<int, 0> a = {0, 1, 2, 3, 4};
-
-  int counter = 5;
-  for (ceres::internal::FixedArray<int>::reverse_iterator iter = a.rbegin();
-       iter != a.rend();
-       ++iter) {
-    counter--;
-    EXPECT_EQ(counter, *iter);
-  }
-  EXPECT_EQ(counter, 0);
-
-  counter = 5;
-  for (ceres::internal::FixedArray<int>::const_reverse_iterator iter =
-           a.rbegin();
-       iter != a.rend();
-       ++iter) {
-    counter--;
-    EXPECT_EQ(counter, *iter);
-  }
-  EXPECT_EQ(counter, 0);
-
-  counter = 5;
-  for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
-    counter--;
-    EXPECT_EQ(counter, *iter);
-  }
-  EXPECT_EQ(counter, 0);
-}
-
-TEST(FixedArrayTest, Fill) {
-  ceres::internal::FixedArray<int, 5 * sizeof(int)> inlined(5);
-  int fill_val = 42;
-  inlined.fill(fill_val);
-  for (int i : inlined) EXPECT_EQ(i, fill_val);
-
-  ceres::internal::FixedArray<int, 0> allocated(5);
-  allocated.fill(fill_val);
-  for (int i : allocated) EXPECT_EQ(i, fill_val);
-
-  // It doesn't do anything, just make sure this compiles.
-  ceres::internal::FixedArray<int> empty(0);
-  empty.fill(fill_val);
-}
-
-// TODO(johnsoncj): Investigate InlinedStorage default initialization in GCC 4.x
-#ifndef __GNUC__
-TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) {
-  using T = char;
-  constexpr auto capacity = 10;
-  using FixedArrType = ceres::internal::FixedArray<T, capacity>;
-  using FixedArrBuffType =
-      typename std::aligned_storage<sizeof(FixedArrType),
-                                    alignof(FixedArrType)>::type;
-  constexpr auto scrubbed_bits = 0x95;
-  constexpr auto length = capacity / 2;
-
-  FixedArrBuffType buff;
-  std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrBuffType));
-
-  FixedArrType* arr =
-      ::new (static_cast<void*>(std::addressof(buff))) FixedArrType(length);
-  EXPECT_THAT(*arr, testing::Each(scrubbed_bits));
-  arr->~FixedArrType();
-}
-#endif  // __GNUC__
-
-// This is a stateful allocator, but the state lives outside of the
-// allocator (in whatever test is using the allocator). This is odd
-// but helps in tests where the allocator is propagated into nested
-// containers - that chain of allocators uses the same state and is
-// thus easier to query for aggregate allocation information.
-template <typename T>
-class CountingAllocator : public std::allocator<T> {
- public:
-  using Alloc = std::allocator<T>;
-  using size_type = typename Alloc::size_type;
-
-  CountingAllocator() = default;
-  explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
-  CountingAllocator(int64_t* b, int64_t* a)
-      : bytes_used_(b), instance_count_(a) {}
-
-  template <typename U>
-  explicit CountingAllocator(const CountingAllocator<U>& x)
-      : Alloc(x),
-        bytes_used_(x.bytes_used_),
-        instance_count_(x.instance_count_) {}
-
-  T* allocate(size_type n) {
-    assert(bytes_used_ != nullptr);
-    *bytes_used_ += n * sizeof(T);
-    return Alloc::allocate(n);
-  }
-
-  void deallocate(T* p, size_type n) {
-    Alloc::deallocate(p, n);
-    assert(bytes_used_ != nullptr);
-    *bytes_used_ -= n * sizeof(T);
-  }
-
-  int64_t* bytes_used_{nullptr};
-  int64_t* instance_count_{nullptr};
-};
-
-TEST(AllocatorSupportTest, CountInlineAllocations) {
-  constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
-  using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
-
-  int64_t allocated = 0;
-  int64_t active_instances = 0;
-
-  {
-    const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
-
-    Alloc alloc(&allocated, &active_instances);
-
-    AllocFxdArr arr(ia, ia + inlined_size, alloc);
-    static_cast<void>(arr);
-  }
-
-  EXPECT_EQ(allocated, 0);
-  EXPECT_EQ(active_instances, 0);
-}
-
-TEST(AllocatorSupportTest, CountOutoflineAllocations) {
-  constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
-  using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
-
-  int64_t allocated = 0;
-  int64_t active_instances = 0;
-
-  {
-    const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
-    Alloc alloc(&allocated, &active_instances);
-
-    AllocFxdArr arr(ia, ia + CERES_INTERNAL_ARRAYSIZE(ia), alloc);
-
-    EXPECT_EQ(allocated, arr.size() * sizeof(int));
-    static_cast<void>(arr);
-  }
-
-  EXPECT_EQ(active_instances, 0);
-}
-
-TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
-  constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
-  using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
-
-  int64_t allocated1 = 0;
-  int64_t allocated2 = 0;
-  int64_t active_instances = 0;
-  Alloc alloc(&allocated1, &active_instances);
-  Alloc alloc2(&allocated2, &active_instances);
-
-  {
-    int initial_value = 1;
-
-    AllocFxdArr arr1(inlined_size / 2, initial_value, alloc);
-
-    EXPECT_EQ(allocated1, 0);
-
-    AllocFxdArr arr2(arr1, alloc2);
-
-    EXPECT_EQ(allocated2, 0);
-    static_cast<void>(arr1);
-    static_cast<void>(arr2);
-  }
-
-  EXPECT_EQ(active_instances, 0);
-}
-
-TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
-  constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
-  using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
-
-  int64_t allocated1 = 0;
-  int64_t allocated2 = 0;
-  int64_t active_instances = 0;
-  Alloc alloc(&allocated1, &active_instances);
-  Alloc alloc2(&allocated2, &active_instances);
-
-  {
-    int initial_value = 1;
-
-    AllocFxdArr arr1(inlined_size * 2, initial_value, alloc);
-
-    EXPECT_EQ(allocated1, arr1.size() * sizeof(int));
-
-    AllocFxdArr arr2(arr1, alloc2);
-
-    EXPECT_EQ(allocated2, inlined_size * 2 * sizeof(int));
-    static_cast<void>(arr1);
-    static_cast<void>(arr2);
-  }
-
-  EXPECT_EQ(active_instances, 0);
-}
-
-TEST(AllocatorSupportTest, SizeValAllocConstructor) {
-  using testing::AllOf;
-  using testing::Each;
-  using testing::SizeIs;
-
-  constexpr size_t inlined_size = 4;
-  using Alloc = CountingAllocator<int>;
-  using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
-
-  {
-    auto len = inlined_size / 2;
-    auto val = 0;
-    int64_t allocated = 0;
-    AllocFxdArr arr(len, val, Alloc(&allocated));
-
-    EXPECT_EQ(allocated, 0);
-    EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
-  }
-
-  {
-    auto len = inlined_size * 2;
-    auto val = 0;
-    int64_t allocated = 0;
-    AllocFxdArr arr(len, val, Alloc(&allocated));
-
-    EXPECT_EQ(allocated, len * sizeof(int));
-    EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
-  }
-}
-
-struct EigenStruct {
-  Eigen::Vector4d data;
-};
-
-static_assert(
-    std::is_same<ceres::internal::FixedArrayDefaultAllocator<double>,
-                 std::allocator<double>>::value,
-    "Double is a trivial type, so std::allocator should be used here.");
-static_assert(
-    std::is_same<ceres::internal::FixedArrayDefaultAllocator<double*>,
-                 std::allocator<double*>>::value,
-    "A pointer is a trivial type, so std::allocator should be used here.");
-static_assert(
-    std::is_same<ceres::internal::FixedArrayDefaultAllocator<Eigen::Matrix4d>,
-                 Eigen::aligned_allocator<Eigen::Matrix4d>>::value,
-    "An Eigen::Matrix4d needs the Eigen::aligned_allocator for proper "
-    "alignment.");
-static_assert(
-    std::is_same<ceres::internal::FixedArrayDefaultAllocator<EigenStruct>,
-                 Eigen::aligned_allocator<EigenStruct>>::value,
-    "A struct containing fixed size Eigen types needs Eigen::aligned_allocator "
-    "for proper alignment.");
-
-}  // namespace
diff --git a/internal/ceres/gradient_checker_test.cc b/internal/ceres/gradient_checker_test.cc
index 5d2ea14..0b9f3a6 100644
--- a/internal/ceres/gradient_checker_test.cc
+++ b/internal/ceres/gradient_checker_test.cc
@@ -37,6 +37,7 @@
 #include <utility>
 #include <vector>
 
+#include "absl/container/fixed_array.h"
 #include "absl/log/check.h"
 #include "absl/log/log.h"
 #include "ceres/cost_function.h"
@@ -206,7 +207,7 @@
   parameter_sizes[2] = 4;
 
   // Make a random set of blocks.
-  FixedArray<double*> parameters(num_parameters);
+  absl::FixedArray<double*> parameters(num_parameters);
   std::mt19937 prng;
   std::uniform_real_distribution<double> distribution(-1.0, 1.0);
   auto randu = [&prng, &distribution] { return distribution(prng); };
diff --git a/internal/ceres/manifold.cc b/internal/ceres/manifold.cc
index bfb2a22..6bd320a 100644
--- a/internal/ceres/manifold.cc
+++ b/internal/ceres/manifold.cc
@@ -5,7 +5,6 @@
 
 #include "absl/log/check.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
 
 namespace ceres {
 namespace {
diff --git a/internal/ceres/problem_impl.cc b/internal/ceres/problem_impl.cc
index eafbb20..cc86d2c 100644
--- a/internal/ceres/problem_impl.cc
+++ b/internal/ceres/problem_impl.cc
@@ -41,6 +41,7 @@
 #include <utility>
 #include <vector>
 
+#include "absl/container/fixed_array.h"
 #include "absl/log/check.h"
 #include "absl/log/log.h"
 #include "ceres/casts.h"
@@ -52,7 +53,6 @@
 #include "ceres/evaluation_callback.h"
 #include "ceres/evaluator.h"
 #include "ceres/internal/export.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/loss_function.h"
 #include "ceres/manifold.h"
 #include "ceres/map_util.h"
@@ -776,7 +776,7 @@
   }
 
   double dummy_cost = 0.0;
-  FixedArray<double, 32> scratch(
+  absl::FixedArray<double> scratch(
       residual_block->NumScratchDoublesForEvaluate());
   return residual_block->Evaluate(apply_loss_function,
                                   cost ? cost : &dummy_cost,
diff --git a/internal/ceres/residual_block.cc b/internal/ceres/residual_block.cc
index da6b88e..aeb761f 100644
--- a/internal/ceres/residual_block.cc
+++ b/internal/ceres/residual_block.cc
@@ -35,12 +35,12 @@
 #include <cstddef>
 #include <vector>
 
+#include "absl/container/fixed_array.h"
 #include "absl/log/check.h"
 #include "absl/log/log.h"
 #include "ceres/corrector.h"
 #include "ceres/cost_function.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/loss_function.h"
 #include "ceres/manifold.h"
 #include "ceres/parameter_block.h"
@@ -77,13 +77,13 @@
 
   // Collect the parameters from their blocks. This will rarely allocate, since
   // residuals taking more than 8 parameter block arguments are rare.
-  FixedArray<const double*, 8> parameters(num_parameter_blocks);
+  absl::FixedArray<const double*> parameters(num_parameter_blocks);
   for (int i = 0; i < num_parameter_blocks; ++i) {
     parameters[i] = parameter_blocks_[i]->state();
   }
 
   // Put pointers into the scratch space into global_jacobians as appropriate.
-  FixedArray<double*, 8> global_jacobians(num_parameter_blocks);
+  absl::FixedArray<double*> global_jacobians(num_parameter_blocks);
   if (jacobians != nullptr) {
     for (int i = 0; i < num_parameter_blocks; ++i) {
       const ParameterBlock* parameter_block = parameter_blocks_[i];
diff --git a/internal/ceres/schur_eliminator_impl.h b/internal/ceres/schur_eliminator_impl.h
index 545f906..6c287fd 100644
--- a/internal/ceres/schur_eliminator_impl.h
+++ b/internal/ceres/schur_eliminator_impl.h
@@ -54,12 +54,12 @@
 #include <map>
 
 #include "Eigen/Dense"
+#include "absl/container/fixed_array.h"
 #include "absl/log/check.h"
 #include "ceres/block_random_access_matrix.h"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/invert_psd_matrix.h"
 #include "ceres/map_util.h"
 #include "ceres/parallel_for.h"
@@ -249,7 +249,7 @@
           ete.setZero();
         }
 
-        FixedArray<double, 8> g(e_block_size);
+        absl::FixedArray<double> g(e_block_size);
         typename EigenTypes<kEBlockSize>::VectorRef gref(g.data(),
                                                          e_block_size);
         gref.setZero();
@@ -283,7 +283,7 @@
         //   rhs = F'b - F'E(E'E)^(-1) E'b
 
         if (rhs) {
-          FixedArray<double, 8> inverse_ete_g(e_block_size);
+          absl::FixedArray<double> inverse_ete_g(e_block_size);
           MatrixVectorMultiply<kEBlockSize, kEBlockSize, 0>(
               inverse_ete.data(),
               e_block_size,
@@ -336,7 +336,7 @@
       const Cell& e_cell = row.cells.front();
       DCHECK_EQ(e_block_id, e_cell.block_id);
 
-      FixedArray<double, 8> sj(row.block.size);
+      absl::FixedArray<double> sj(row.block.size);
 
       typename EigenTypes<kRowBlockSize>::VectorRef(sj.data(), row.block.size) =
           typename EigenTypes<kRowBlockSize>::ConstVectorRef(