pw_containers: Vector class

pw::Vector implements the std::vector interface, but uses a fixed size
buffer instead of dynamically allocated memory. Vectors must be declared
with their max size (Vector<Type, kMaxSize>) but may be referred to
without the max size (Vector<Type>).

Change-Id: Iac16996109b55fdf8fce73a97e8e84072eb8d166
diff --git a/BUILD.gn b/BUILD.gn
index 26e58c0..6ef3c54 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -81,6 +81,7 @@
     "$dir_pw_assert:tests",
     "$dir_pw_base64:tests",
     "$dir_pw_checksum:tests",
+    "$dir_pw_containers:tests",
     "$dir_pw_log:tests",
     "$dir_pw_polyfill:tests",
     "$dir_pw_preprocessor:tests",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2c3c59d..f16ca06 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,6 +21,7 @@
 add_subdirectory(pw_assert)
 add_subdirectory(pw_base64)
 add_subdirectory(pw_checksum)
+add_subdirectory(pw_containers)
 add_subdirectory(pw_cpu_exception)
 add_subdirectory(pw_cpu_exception_armv7m)
 add_subdirectory(pw_dumb_io)
diff --git a/modules.gni b/modules.gni
index 9bf257b..6138f24 100644
--- a/modules.gni
+++ b/modules.gni
@@ -23,6 +23,7 @@
 dir_pw_boot_armv7m = "$dir_pigweed/pw_boot_armv7m"
 dir_pw_build = "$dir_pigweed/pw_build"
 dir_pw_checksum = "$dir_pigweed/pw_checksum"
+dir_pw_containers = "$dir_pigweed/pw_containers"
 dir_pw_cpu_exception = "$dir_pigweed/pw_cpu_exception"
 dir_pw_cpu_exception_armv7m = "$dir_pigweed/pw_cpu_exception_armv7m"
 dir_pw_docgen = "$dir_pigweed/pw_docgen"
diff --git a/pw_containers/BUILD b/pw_containers/BUILD
new file mode 100644
index 0000000..ee0f194
--- /dev/null
+++ b/pw_containers/BUILD
@@ -0,0 +1,39 @@
+# Copyright 2020 The Pigweed 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.
+
+load(
+    "//pw_build:pigweed.bzl",
+    "pw_cc_library",
+    "pw_cc_test",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache License 2.0
+
+pw_cc_library(
+    name = "pw_containers",
+    hdrs = [
+        "public/pw_containers/vector.h",
+    ],
+    includes = ["public"],
+)
+
+pw_cc_test(
+    name = "vector_test",
+    srcs = [
+        "vector_test.cc",
+    ],
+    deps = ["//pw_containers"],
+)
diff --git a/pw_containers/BUILD.gn b/pw_containers/BUILD.gn
new file mode 100644
index 0000000..eefaa6d
--- /dev/null
+++ b/pw_containers/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright 2019 The Pigweed 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.
+
+import("$dir_pw_unit_test/test.gni")
+
+config("default_config") {
+  include_dirs = [ "public" ]
+}
+
+source_set("pw_containers") {
+  public_configs = [ ":default_config" ]
+  public = [
+    "public/pw_containers/vector.h",
+  ]
+  sources = public
+}
+
+pw_test_group("tests") {
+  tests = [ ":vector_test" ]
+}
+
+pw_test("vector_test") {
+  deps = [
+    ":pw_containers",
+  ]
+  sources = [
+    "vector_test.cc",
+  ]
+}
diff --git a/pw_containers/CMakeLists.txt b/pw_containers/CMakeLists.txt
new file mode 100644
index 0000000..4ee6137
--- /dev/null
+++ b/pw_containers/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright 2020 The Pigweed 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.
+
+pw_auto_add_simple_module(pw_containers)
diff --git a/pw_containers/public/pw_containers/vector.h b/pw_containers/public/pw_containers/vector.h
new file mode 100644
index 0000000..57f5321
--- /dev/null
+++ b/pw_containers/public/pw_containers/vector.h
@@ -0,0 +1,432 @@
+// Copyright 2020 The Pigweed 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.
+#pragma once
+
+#include <algorithm>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace pw {
+namespace vector_impl {
+
+template <typename I>
+using IsIterator = std::negation<
+    std::is_same<typename std::iterator_traits<I>::value_type, void>>;
+
+// Used as kMaxSize in the generic-size Vector<T> interface.
+inline constexpr size_t kGeneric = size_t(-1);
+
+}  // namespace vector_impl
+
+// The Vector class is similar to std::vector, except it is backed by a
+// fixed-size buffer. Vectors must be declared with an explicit maximum size
+// (e.g. Vector<int, 10>) but vectors can be used and referred to without the
+// max size template parameter (e.g. Vector<int>).
+//
+// To allow referring to a pw::Vector without an explicit maximum size, all
+// Vector classes inherit from Vector<T, vector_impl::kGeneric>, which stores
+// the maximum size in a variable. This allows Vectors to be used without having
+// to know their maximum size at compile time. It also keeps code size small
+// since function implementations are shared for all maximum sizes.
+template <typename T, size_t kMaxSize = vector_impl::kGeneric>
+class Vector : public Vector<T, vector_impl::kGeneric> {
+ public:
+  using value_type = T;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using iterator = T*;
+  using const_iterator = const T*;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+  // Construct
+  Vector() noexcept : Vector<T, vector_impl::kGeneric>(kMaxSize) {}
+
+  Vector(size_type count, const T& value)
+      : Vector<T, vector_impl::kGeneric>(kMaxSize, count, value) {}
+
+  explicit Vector(size_type count)
+      : Vector<T, vector_impl::kGeneric>(kMaxSize, count, T()) {}
+
+  template <
+      typename Iterator,
+      typename...,
+      typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
+  Vector(Iterator first, Iterator last)
+      : Vector<T, vector_impl::kGeneric>(kMaxSize, first, last) {}
+
+  template <size_t kOtherMaxSize>
+  Vector(const Vector<T, kOtherMaxSize>& other)
+      : Vector<T, vector_impl::kGeneric>(kMaxSize, other) {}
+
+  template <size_t kOtherMaxSize>
+  Vector(Vector<T, kOtherMaxSize>&& other) noexcept
+      : Vector<T, vector_impl::kGeneric>(kMaxSize, std::move(other)) {}
+
+  Vector(std::initializer_list<T> list)
+      : Vector<T, vector_impl::kGeneric>(kMaxSize, list) {}
+
+  Vector& operator=(const Vector& other) {
+    Vector<T>::assign(other.begin(), other.end());
+    return *this;
+  }
+
+  template <size_t kOtherMaxSize>
+  Vector& operator=(const Vector<T, kOtherMaxSize>& other) noexcept {
+    Vector<T>::assign(other.begin(), other.end());
+    return *this;
+  }
+
+  Vector& operator=(Vector&& other) noexcept {
+    Vector<T>::operator=(std::move(other));
+    return *this;
+  }
+
+  template <size_t kOtherMaxSize>
+  Vector& operator=(Vector<T, kOtherMaxSize>&& other) noexcept {
+    Vector<T>::operator=(std::move(other));
+    return *this;
+  }
+
+  Vector& operator=(std::initializer_list<T> list) {
+    this->assign(list.begin(), list.end());
+    return *this;
+  }
+
+  static constexpr size_type max_size() noexcept { return kMaxSize; }
+
+  // All other vector methods are implemented on the Vector<T> base class.
+
+ private:
+  friend class Vector<T, vector_impl::kGeneric>;
+
+  // Provides access to the underlying array as an array of T.
+  pointer array() { return std::launder(reinterpret_cast<T*>(&array_)); }
+  const_pointer array() const {
+    return std::launder(reinterpret_cast<const T*>(&array_));
+  }
+
+  // Vector entries are stored as uninitialized memory blocks aligned correctly
+  // for the type. Elements are initialized on demand with placement new.
+  std::aligned_storage_t<sizeof(T), alignof(T)> array_[kMaxSize];
+};
+
+// Defines the generic-sized Vector<T> specialization, which serves as the base
+// class for Vector<T> of any maximum size. Except for constructors, all Vector
+// methods are implemented on this class.
+template <typename T>
+class Vector<T, vector_impl::kGeneric> {
+ public:
+  using value_type = T;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using iterator = T*;
+  using const_iterator = const T*;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+  // A vector without an explicit maximum size (Vector<T>) cannot be constructed
+  // directly. Instead, construct a Vector<T, max_size>. Vectors of any max size
+  // can be used through a Vector<T> pointer or reference.
+
+  ~Vector() { clear(); }
+
+  // Assign
+
+  Vector& operator=(const Vector& other) {
+    assign(other.begin(), other.end());
+    return *this;
+  }
+
+  Vector& operator=(Vector&& other) noexcept {
+    clear();
+    MoveFrom(other);
+    return *this;
+  }
+
+  Vector& operator=(std::initializer_list<T> list) {
+    assign(list);
+    return *this;
+  }
+
+  void assign(size_type count, const T& value) {
+    clear();
+    Append(count, value);
+  }
+
+  template <
+      typename Iterator,
+      typename...,
+      typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
+  void assign(Iterator first, Iterator last) {
+    clear();
+    CopyFrom(first, last);
+  }
+
+  void assign(std::initializer_list<T> list) {
+    assign(list.begin(), list.end());
+  }
+
+  // Access
+
+  // TODO(hepler): Add an assert for bounds checking in at.
+  reference at(size_type index) { return data()[index]; }
+  const_reference at(size_type index) const { return data()[index]; }
+
+  reference operator[](size_type index) { return data()[index]; }
+  const_reference operator[](size_type index) const { return data()[index]; }
+
+  reference front() { return data()[0]; }
+  const_reference front() const { return data()[0]; }
+
+  reference back() { return data()[size() - 1]; }
+  const_reference back() const { return data()[size() - 1]; }
+
+  // The underlying data is not part of the generic-length vector class. It is
+  // provided in the derived class from which this instance was constructed. To
+  // access the data, down-cast this to a Vector with a known max size, and
+  // return a pointer to the start of the array, which is the same for all
+  // vectors with explicit max size.
+  T* data() noexcept { return static_cast<Vector<T, 1>*>(this)->array(); }
+  const T* data() const noexcept {
+    return static_cast<const Vector<T, 1>*>(this)->array();
+  }
+
+  // Iterate
+
+  iterator begin() noexcept { return &data()[0]; }
+  const_iterator begin() const noexcept { return &data()[0]; }
+  const_iterator cbegin() const noexcept { return &data()[0]; }
+
+  iterator end() noexcept { return &data()[size()]; }
+  const_iterator end() const noexcept { return &data()[size()]; }
+  const_iterator cend() const noexcept { return &data()[size()]; }
+
+  reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const { return reverse_iterator(end()); }
+  const_reverse_iterator crbegin() const noexcept {
+    return reverse_iterator(cend());
+  }
+
+  reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const { return reverse_iterator(begin()); }
+  const_reverse_iterator crend() const noexcept {
+    return reverse_iterator(cbegin());
+  }
+
+  // Size
+
+  [[nodiscard]] bool empty() const noexcept { return size() == 0u; }
+
+  [[nodiscard]] bool full() const noexcept { return size() == max_size(); }
+
+  size_type size() const noexcept { return size_; }
+
+  size_type max_size() const noexcept { return max_size_; }
+
+  size_type capacity() const noexcept { return max_size(); }
+
+  // Modify
+
+  void clear() noexcept;
+
+  // TODO(hepler): insert, emplace, and erase are not yet implemented.
+  //    Currently, items can only be added to or removed from the end.
+  iterator insert(const_iterator index, const T& value);
+
+  iterator insert(const_iterator index, T&& value);
+
+  iterator insert(const_iterator index, size_type count, const T& value);
+
+  template <typename Iterator>
+  iterator insert(const_iterator index, Iterator first, Iterator last);
+
+  iterator insert(const_iterator index, std::initializer_list<T> list);
+
+  template <typename... Args>
+  iterator emplace(const_iterator index, Args&&... args);
+
+  iterator erase(const_iterator index);
+
+  iterator erase(const_iterator first, const_iterator last);
+
+  void push_back(const T& value) { emplace_back(value); }
+
+  void push_back(T&& value) { emplace_back(std::move(value)); }
+
+  template <typename... Args>
+  void emplace_back(Args&&... args);
+
+  void pop_back();
+
+  void resize(size_type new_size) { resize(new_size, T()); }
+
+  void resize(size_type new_size, const T& value);
+
+ protected:
+  // Vectors without an explicit size cannot be constructed directly. Instead,
+  // the maximum size must be provided.
+  explicit Vector(size_type max_size) noexcept : max_size_(max_size) {}
+
+  Vector(size_type max_size, size_type count, const T& value)
+      : Vector(max_size) {
+    Append(count, value);
+  }
+
+  Vector(size_type max_size, size_type count) : Vector(max_size, count, T()) {}
+
+  template <
+      typename Iterator,
+      typename...,
+      typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
+  Vector(size_type max_size, Iterator first, Iterator last) : Vector(max_size) {
+    CopyFrom(first, last);
+  }
+
+  Vector(size_type max_size, const Vector& other) : Vector(max_size) {
+    CopyFrom(other.begin(), other.end());
+  }
+
+  Vector(size_type max_size, Vector&& other) noexcept : Vector(max_size) {
+    MoveFrom(other);
+  }
+
+  Vector(size_type max_size, std::initializer_list<T> list) : Vector(max_size) {
+    CopyFrom(list.begin(), list.end());
+  }
+
+ private:
+  template <typename Iterator>
+  void CopyFrom(Iterator first, Iterator last);
+
+  void MoveFrom(Vector& other) noexcept;
+
+  void Append(size_type count, const T& value);
+
+  const size_type max_size_;
+  size_type size_ = 0;
+};
+
+// Compare
+
+template <typename T, size_t kLhsSize, size_t kRhsSize>
+bool operator==(const Vector<T, kLhsSize>& lhs,
+                const Vector<T, kRhsSize>& rhs) {
+  return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
+
+template <typename T, size_t kLhsSize, size_t kRhsSize>
+bool operator!=(const Vector<T, kLhsSize>& lhs,
+                const Vector<T, kRhsSize>& rhs) {
+  return !(lhs == rhs);
+}
+
+template <typename T, size_t kLhsSize, size_t kRhsSize>
+bool operator<(const Vector<T, kLhsSize>& lhs, const Vector<T, kRhsSize>& rhs) {
+  return std::lexicographical_compare(
+      lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
+
+template <typename T, size_t kLhsSize, size_t kRhsSize>
+bool operator<=(const Vector<T, kLhsSize>& lhs,
+                const Vector<T, kRhsSize>& rhs) {
+  return !(rhs < lhs);
+}
+
+template <typename T, size_t kLhsSize, size_t kRhsSize>
+bool operator>(const Vector<T, kLhsSize>& lhs, const Vector<T, kRhsSize>& rhs) {
+  return rhs < lhs;
+}
+
+template <typename T, size_t kLhsSize, size_t kRhsSize>
+bool operator>=(const Vector<T, kLhsSize>& lhs,
+                const Vector<T, kRhsSize>& rhs) {
+  return !(lhs < rhs);
+}
+
+// Function implementations
+
+template <typename T>
+void Vector<T, vector_impl::kGeneric>::clear() noexcept {
+  for (auto& item : *this) {
+    item.~T();
+  }
+  size_ = 0;
+}
+
+template <typename T>
+template <typename... Args>
+void Vector<T, vector_impl::kGeneric>::emplace_back(Args&&... args) {
+  if (!full()) {
+    new (&data()[size_]) T(std::forward<Args>(args)...);
+    size_ += 1;
+  }
+}
+
+template <typename T>
+void Vector<T, vector_impl::kGeneric>::pop_back() {
+  if (!empty()) {
+    back().~T();
+    size_ -= 1;
+  }
+}
+
+template <typename T>
+void Vector<T, vector_impl::kGeneric>::resize(size_type new_size,
+                                              const T& value) {
+  if (size() < new_size) {
+    Append(std::min(max_size(), new_size) - size(), value);
+  } else {
+    while (size() > new_size) {
+      pop_back();
+    }
+  }
+}
+
+template <typename T>
+template <typename Iterator>
+void Vector<T, vector_impl::kGeneric>::CopyFrom(Iterator first, Iterator last) {
+  while (first != last) {
+    push_back(*first++);
+  }
+}
+
+template <typename T>
+void Vector<T, vector_impl::kGeneric>::MoveFrom(Vector& other) noexcept {
+  for (auto&& item : other) {
+    emplace_back(std::move(item));
+  }
+  other.clear();
+}
+
+template <typename T>
+void Vector<T, vector_impl::kGeneric>::Append(size_type count, const T& value) {
+  for (size_t i = 0; i < count; ++i) {
+    push_back(value);
+  }
+}
+
+}  // namespace pw
diff --git a/pw_containers/vector_test.cc b/pw_containers/vector_test.cc
new file mode 100644
index 0000000..5e214d1
--- /dev/null
+++ b/pw_containers/vector_test.cc
@@ -0,0 +1,429 @@
+// Copyright 2020 The Pigweed 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 "pw_containers/vector.h"
+
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace pw {
+namespace {
+
+struct CopyOnly {
+  explicit CopyOnly(int value) : value(value) {}
+
+  CopyOnly(const CopyOnly& other) { value = other.value; }
+
+  CopyOnly& operator=(const CopyOnly& other) {
+    value = other.value;
+    return *this;
+  }
+
+  CopyOnly(CopyOnly&&) = delete;
+
+  int value;
+};
+
+struct MoveOnly {
+  explicit MoveOnly(int value) : value(value) {}
+
+  MoveOnly(const MoveOnly&) = delete;
+
+  MoveOnly(MoveOnly&& other) {
+    value = other.value;
+    other.value = kDeleted;
+  }
+
+  static constexpr int kDeleted = -1138;
+
+  int value;
+};
+
+struct Counter {
+  static int created;
+  static int destroyed;
+  static int moved;
+
+  static void Reset() { created = destroyed = moved = 0; }
+
+  Counter() : value(0) { created += 1; }
+
+  Counter(int val) : value(val) { created += 1; }
+
+  Counter(const Counter& other) : value(other.value) { created += 1; }
+
+  Counter(Counter&& other) : value(other.value) {
+    other.value = 0;
+    moved += 1;
+  }
+
+  ~Counter() { destroyed += 1; }
+
+  int value;
+};
+
+int Counter::created = 0;
+int Counter::destroyed = 0;
+int Counter::moved = 0;
+
+TEST(Vector, Construct_NoArg) {
+  Vector<int, 3> vector;
+  EXPECT_TRUE(vector.empty());
+}
+
+TEST(Vector, Construct_MultipleCopies) {
+  Vector<int, 3> vector(3, 123);
+
+  EXPECT_EQ(vector.size(), 3u);
+  EXPECT_EQ(vector[0], 123);
+  EXPECT_EQ(vector[1], 123);
+  EXPECT_EQ(vector[2], 123);
+}
+
+TEST(Vector, Construct_DefaultSize) {
+  Vector<int, 3> vector(3);
+
+  EXPECT_EQ(vector.size(), 3u);
+  EXPECT_EQ(vector[0], 0);
+  EXPECT_EQ(vector[1], 0);
+  EXPECT_EQ(vector[2], 0);
+}
+
+TEST(Vector, Construct_Iterators) {
+  std::array array{1, 2, 3, 4, 5};
+
+  Vector<int, 64> vector(array.begin(), array.end());
+
+  EXPECT_EQ(vector.size(), array.size());
+  for (size_t i = 0; i < array.size(); ++i) {
+    EXPECT_EQ(vector[i], array[i]);
+  }
+}
+
+TEST(Vector, Construct_Copy) {
+  CopyOnly origin(5);
+  Vector<CopyOnly, 10> origin_vector(3, origin);
+
+  Vector<CopyOnly, 100> vector(origin_vector);
+
+  EXPECT_EQ(3u, vector.size());
+
+  for (size_t i = 0; i < vector.size(); ++i) {
+    EXPECT_EQ(vector[i].value, origin.value);
+  }
+}
+
+TEST(Vector, Construct_Move) {
+  Vector<MoveOnly, 10> origin_vector;
+
+  for (int i = 0; i < 5; ++i) {
+    origin_vector.emplace_back(421);
+  }
+
+  Vector<MoveOnly, 100> vector(std::move(origin_vector));
+
+  EXPECT_EQ(5u, vector.size());
+
+  for (size_t i = 0; i < vector.size(); ++i) {
+    EXPECT_EQ(vector[i].value, 421);
+  }
+
+  for (size_t i = 0; i < origin_vector.size(); ++i) {
+    EXPECT_EQ(origin_vector[i].value, MoveOnly::kDeleted);
+  }
+}
+
+TEST(Vector, Construct_InitializerList) {
+  Vector<int, 3> vector{100, 200};
+  EXPECT_EQ(vector.size(), 2u);
+  EXPECT_EQ(vector[0], 100);
+  EXPECT_EQ(vector[1], 200);
+}
+
+TEST(Vector, Destruct_ZeroLength) {
+  Counter::Reset();
+
+  { Vector<Counter, 0> destroyed; }
+  EXPECT_EQ(Counter::created, 0);
+  EXPECT_EQ(Counter::destroyed, 0);
+}
+
+TEST(Vector, Destruct_Empty) {
+  Counter::Reset();
+
+  { Vector<Counter, 128> destroyed; }
+  EXPECT_EQ(Counter::created, 0);
+  EXPECT_EQ(Counter::destroyed, 0);
+}
+
+TEST(Vector, Destruct_MultpileEntries) {
+  Counter value;
+  Counter::Reset();
+
+  { Vector<Counter, 128> destroyed(100, value); }
+
+  EXPECT_EQ(Counter::created, 100);
+  EXPECT_EQ(Counter::destroyed, 100);
+}
+
+TEST(Vector, Assign_Copy_SmallerToLarger) {
+  CopyOnly origin(5);
+  Vector<CopyOnly, 3> origin_vector(3, origin);
+
+  Vector<CopyOnly, 2> vector;
+  vector = origin_vector;
+
+  EXPECT_EQ(2u, vector.size());
+
+  for (size_t i = 0; i < vector.size(); ++i) {
+    EXPECT_EQ(vector[i].value, origin.value);
+  }
+}
+
+TEST(Vector, Assign_DifferentMaxSize_Copy) {
+  const Vector<int, 10> origin_vector = {1, 1, 2, 3};
+
+  Vector<int, 100> vector;
+  vector = origin_vector;
+
+  ASSERT_EQ(4u, vector.size());
+  EXPECT_EQ(1, vector[0]);
+  EXPECT_EQ(1, vector[1]);
+  EXPECT_EQ(2, vector[2]);
+  EXPECT_EQ(3, vector[3]);
+}
+
+TEST(Vector, Assign_SameMaxSize_Copy) {
+  const Vector<int, 10> origin_vector = {1, 1, 2, 3};
+
+  Vector<int, 10> vector;
+  vector = origin_vector;
+
+  ASSERT_EQ(4u, vector.size());
+  EXPECT_EQ(1, vector[0]);
+  EXPECT_EQ(1, vector[1]);
+  EXPECT_EQ(2, vector[2]);
+  EXPECT_EQ(3, vector[3]);
+}
+
+TEST(Vector, Assign_Generic_Copy) {
+  const Vector<int, 10> origin_vector = {1, 1, 2, 3};
+
+  Vector<int, 10> vector;
+  Vector<int>& ref = vector;
+  ref = static_cast<const Vector<int>&>(origin_vector);
+
+  ASSERT_EQ(4u, vector.size());
+  EXPECT_EQ(1, vector[0]);
+  EXPECT_EQ(1, vector[1]);
+  EXPECT_EQ(2, vector[2]);
+  EXPECT_EQ(3, vector[3]);
+}
+
+TEST(Vector, Assign_Move) {
+  Vector<MoveOnly, 10> origin_vector;
+
+  for (int i = 0; i < 5; ++i) {
+    origin_vector.emplace_back(421);
+  }
+
+  Vector<MoveOnly, 10> vector;
+  vector = std::move(origin_vector);
+
+  EXPECT_EQ(5u, vector.size());
+
+  for (size_t i = 0; i < vector.size(); ++i) {
+    EXPECT_EQ(vector[i].value, 421);
+  }
+
+  for (size_t i = 0; i < origin_vector.size(); ++i) {
+    EXPECT_EQ(origin_vector[i].value, MoveOnly::kDeleted);
+  }
+}
+
+TEST(Vector, Assign_InitializerList) {
+  Vector<int, 4> vector;
+  vector = {1, 3, 5, 7, 9};
+
+  EXPECT_EQ(4u, vector.size());
+
+  EXPECT_EQ(1, vector[0]);
+  EXPECT_EQ(3, vector[1]);
+  EXPECT_EQ(5, vector[2]);
+  EXPECT_EQ(7, vector[3]);
+}
+
+TEST(Vector, Access_ZeroLength) {
+  Vector<Counter, 0> vector;
+
+  EXPECT_EQ(0u, vector.size());
+  EXPECT_EQ(0u, vector.max_size());
+  EXPECT_TRUE(vector.empty());
+  EXPECT_TRUE(vector.full());
+
+  for (auto& item : vector) {
+    (void)item;
+    FAIL();
+  }
+}
+
+TEST(Vector, Access_Data_ArrayLocationIsIndependentOfMaxSize) {
+  Vector<int, 10> vector;
+  Vector<int>& base = static_cast<Vector<int>&>(vector);
+
+  EXPECT_EQ(vector.data(), base.data());
+  EXPECT_EQ(vector.data(), (static_cast<Vector<int, 0>&>(base).data()));
+  EXPECT_EQ(vector.data(), (static_cast<Vector<int, 1>&>(base).data()));
+  EXPECT_EQ(vector.data(), (static_cast<Vector<int, 100>&>(base).data()));
+  EXPECT_EQ(vector.data(), (static_cast<Vector<int, 999>&>(base).data()));
+}
+
+TEST(Vector, Modify_Clear) {
+  Counter::Reset();
+
+  Vector<Counter, 100> vector;
+  vector.emplace_back();
+  vector.emplace_back();
+  vector.emplace_back();
+
+  vector.clear();
+
+  EXPECT_EQ(3, Counter::created);
+  EXPECT_EQ(3, Counter::destroyed);
+}
+
+TEST(Vector, Modify_PushBack_Copy) {
+  Counter value(99);
+  Counter::Reset();
+
+  {
+    Vector<Counter, 10> vector;
+    vector.push_back(value);
+
+    EXPECT_EQ(vector.size(), 1u);
+    EXPECT_EQ(vector.front().value, 99);
+  }
+
+  EXPECT_EQ(Counter::created, 1);
+  EXPECT_EQ(Counter::destroyed, 1);
+}
+
+TEST(Vector, Modify_PushBack_Move) {
+  Counter::Reset();
+
+  {
+    Counter value(99);
+    Vector<Counter, 10> vector;
+    vector.push_back(std::move(value));
+
+    EXPECT_EQ(vector.size(), 1u);
+    EXPECT_EQ(vector.front().value, 99);
+    EXPECT_EQ(value.value, 0);
+  }
+
+  EXPECT_EQ(Counter::created, 1);
+  EXPECT_EQ(Counter::destroyed, 2);
+  EXPECT_EQ(Counter::moved, 1);
+}
+
+TEST(Vector, Modify_EmplaceBack) {
+  Counter::Reset();
+
+  {
+    Vector<Counter, 10> vector;
+    vector.emplace_back(314);
+
+    EXPECT_EQ(vector.size(), 1u);
+    EXPECT_EQ(vector.front().value, 314);
+  }
+
+  EXPECT_EQ(Counter::created, 1);
+  EXPECT_EQ(Counter::destroyed, 1);
+}
+
+TEST(Vector, Modify_Resize_Larger) {
+  Vector<CopyOnly, 10> vector(1, CopyOnly(123));
+  vector.resize(3, CopyOnly(123));
+
+  EXPECT_EQ(vector.size(), 3u);
+  for (auto& i : vector) {
+    EXPECT_EQ(i.value, 123);
+  }
+}
+
+TEST(Vector, Modify_Resize_LargerThanMax) {
+  Vector<CopyOnly, 10> vector;
+  vector.resize(1000, CopyOnly(123));
+
+  EXPECT_EQ(vector.size(), 10u);
+  for (auto& i : vector) {
+    EXPECT_EQ(i.value, 123);
+  }
+}
+
+TEST(Vector, Modify_Resize_Smaller) {
+  Vector<CopyOnly, 10> vector(9, CopyOnly(123));
+  vector.resize(3, CopyOnly(123));
+
+  EXPECT_EQ(vector.size(), 3u);
+  for (auto& i : vector) {
+    EXPECT_EQ(i.value, 123);
+  }
+}
+
+TEST(Vector, Modify_PopBack) {
+  Vector<Counter, 10> vector({Counter(1), Counter(2), Counter(3)});
+  Counter::Reset();
+
+  vector.pop_back();
+
+  EXPECT_EQ(vector.size(), 2u);
+  EXPECT_EQ(vector[0].value, 1);
+  EXPECT_EQ(vector[1].value, 2);
+
+  EXPECT_EQ(Counter::created, 0);
+  EXPECT_EQ(Counter::destroyed, 1);
+}
+
+TEST(Vector, Modify_Resize_Zero) {
+  Vector<CopyOnly, 10> vector(10, CopyOnly(123));
+  vector.resize(0, CopyOnly(123));
+
+  EXPECT_EQ(vector.size(), 0u);
+}
+
+TEST(Vector, Generic) {
+  Vector<int, 10> vector{1, 2, 3, 4, 5};
+
+  Vector<int>& generic_vector(vector);
+
+  EXPECT_EQ(generic_vector.size(), vector.size());
+  EXPECT_EQ(generic_vector.max_size(), vector.max_size());
+
+  int i = 0;
+  for (int value : vector) {
+    EXPECT_EQ(value, generic_vector[i]);
+    i += 1;
+  }
+
+  i = 0;
+  for (int value : generic_vector) {
+    EXPECT_EQ(vector[i], value);
+    i += 1;
+  }
+}
+
+}  // namespace
+}  // namespace pw