pw_minimal_cpp_stdlib: Extremely limited C++ lib

pw_minimal_cpp_stdlib is an extremely limited, non-standard
implementation of the C++ Standard Library. It requires C++17 and a C
standard library.

Change-Id: I2d0b8d6cf49730e2c746eddf2c4a23308af1eb6a
diff --git a/BUILD.gn b/BUILD.gn
index 6379134..355b961 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# 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
@@ -54,6 +54,7 @@
     "$dir_pw_base64",
     "$dir_pw_checksum",
     "$dir_pw_kvs",
+    "$dir_pw_minimal_cpp_stdlib",
     "$dir_pw_polyfill",
     "$dir_pw_preprocessor",
     "$dir_pw_protobuf",
@@ -73,6 +74,7 @@
     "$dir_pw_checksum:tests",
     "$dir_pw_kvs:tests",
     "$dir_pw_log:tests",
+    "$dir_pw_minimal_cpp_stdlib:tests",
     "$dir_pw_polyfill:tests",
     "$dir_pw_preprocessor:tests",
     "$dir_pw_protobuf:tests",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8ed777..3e6b40d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,7 @@
 add_subdirectory(pw_kvs)
 add_subdirectory(pw_log)
 add_subdirectory(pw_log_basic)
+add_subdirectory(pw_minimal_cpp_stdlib)
 add_subdirectory(pw_polyfill)
 add_subdirectory(pw_preprocessor)
 add_subdirectory(pw_span)
diff --git a/docs/BUILD.gn b/docs/BUILD.gn
index 031834e..076900d 100644
--- a/docs/BUILD.gn
+++ b/docs/BUILD.gn
@@ -51,6 +51,7 @@
     "$dir_pw_dumb_io_baremetal_stm32f429:docs",
     "$dir_pw_dumb_io_stdio:docs",
     "$dir_pw_log:docs",
+    "$dir_pw_minimal_cpp_stdlib:docs",
     "$dir_pw_module:docs",
     "$dir_pw_polyfill:docs",
     "$dir_pw_preprocessor:docs",
diff --git a/modules.gni b/modules.gni
index 41fe5cf..d543d55 100644
--- a/modules.gni
+++ b/modules.gni
@@ -32,6 +32,7 @@
 dir_pw_kvs = "$dir_pigweed/pw_kvs"
 dir_pw_log = "$dir_pigweed/pw_log"
 dir_pw_log_basic = "$dir_pigweed/pw_log_basic"
+dir_pw_minimal_cpp_stdlib = "$dir_pigweed/pw_minimal_cpp_stdlib"
 dir_pw_module = "$dir_pigweed/pw_module"
 dir_pw_polyfill = "$dir_pigweed/pw_polyfill"
 dir_pw_preprocessor = "$dir_pigweed/pw_preprocessor"
diff --git a/pw_minimal_cpp_stdlib/BUILD b/pw_minimal_cpp_stdlib/BUILD
new file mode 100644
index 0000000..3e39d7b
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/BUILD
@@ -0,0 +1,70 @@
+# 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",
+)
+
+pw_cc_library(
+    name = "pw_minimal_cpp_stdlib",
+    srcs = [
+        "public/internal/algorithm.h",
+        "public/internal/array.h",
+        "public/internal/cinttypes.h",
+        "public/internal/cmath.h",
+        "public/internal/cstdarg.h",
+        "public/internal/cstddef.h",
+        "public/internal/cstdint.h",
+        "public/internal/cstdio.h",
+        "public/internal/cstring.h",
+        "public/internal/iterator.h",
+        "public/internal/limits.h",
+        "public/internal/new.h",
+        "public/internal/string_view.h",
+        "public/internal/type_traits.h",
+        "public/internal/utility.h",
+    ],
+    hdrs = [
+        "public/algorithm",
+        "public/array",
+        "public/cinttypes",
+        "public/cmath",
+        "public/cstdarg",
+        "public/cstddef",
+        "public/cstdint",
+        "public/cstdio",
+        "public/cstring",
+        "public/iterator",
+        "public/limits",
+        "public/new",
+        "public/string_view",
+        "public/type_traits",
+        "public/utility",
+    ],
+    copts = ["-nostdinc++"],
+    includes = ["public"],
+)
+
+pw_cc_test(
+    name = "test",
+    srcs = [
+        "test.cc",
+    ],
+    copts = ["-nostdinc++"],
+    deps = [
+        ":pw_minimal_cpp_stdlib",
+    ],
+)
diff --git a/pw_minimal_cpp_stdlib/BUILD.gn b/pw_minimal_cpp_stdlib/BUILD.gn
new file mode 100644
index 0000000..d9ac40f
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/BUILD.gn
@@ -0,0 +1,92 @@
+# 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.
+
+import("$dir_pw_docgen/docs.gni")
+import("$dir_pw_unit_test/test.gni")
+
+config("include_dirs") {
+  include_dirs = [ "public" ]
+}
+
+config("no_cpp_includes") {
+  cflags = [ "-nostdinc++" ]
+}
+
+source_set("pw_minimal_cpp_stdlib") {
+  public_configs = [ ":include_dirs" ]
+  configs = [ ":no_cpp_includes" ]
+  public = [
+    "public/algorithm",
+    "public/array",
+    "public/cinttypes",
+    "public/cmath",
+    "public/cstdarg",
+    "public/cstddef",
+    "public/cstdint",
+    "public/cstdio",
+    "public/cstring",
+    "public/iterator",
+    "public/limits",
+    "public/new",
+    "public/string_view",
+    "public/type_traits",
+    "public/utility",
+  ]
+  sources = [
+    "public/internal/algorithm.h",
+    "public/internal/array.h",
+    "public/internal/cinttypes.h",
+    "public/internal/cmath.h",
+    "public/internal/cstdarg.h",
+    "public/internal/cstddef.h",
+    "public/internal/cstdint.h",
+    "public/internal/cstdio.h",
+    "public/internal/cstring.h",
+    "public/internal/iterator.h",
+    "public/internal/limits.h",
+    "public/internal/new.h",
+    "public/internal/string_view.h",
+    "public/internal/type_traits.h",
+    "public/internal/utility.h",
+  ]
+}
+
+pw_test_group("tests") {
+  tests = [
+    ":minimal_cpp_stdlib_test",
+    ":standard_library_test",
+  ]
+}
+
+pw_test("minimal_cpp_stdlib_test") {
+  configs = [ ":no_cpp_includes" ]
+  deps = [
+    ":pw_minimal_cpp_stdlib",
+  ]
+  sources = [
+    "test.cc",
+  ]
+}
+
+pw_test("standard_library_test") {
+  sources = [
+    "test.cc",
+  ]
+}
+
+pw_doc_group("docs") {
+  sources = [
+    "docs.rst",
+  ]
+}
diff --git a/pw_minimal_cpp_stdlib/CMakeLists.txt b/pw_minimal_cpp_stdlib/CMakeLists.txt
new file mode 100644
index 0000000..90f96cd
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/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_minimal_cpp_stdlib)
diff --git a/pw_minimal_cpp_stdlib/docs.rst b/pw_minimal_cpp_stdlib/docs.rst
new file mode 100644
index 0000000..904f369
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/docs.rst
@@ -0,0 +1,31 @@
+.. _chapter-pw-minimal-cpp-stdlib:
+
+.. default-domain:: cpp
+
+---------------------
+pw_minimal_cpp_stdlib
+---------------------
+The pw_minimal_cpp_stdlib module provides an extremely limited implementation of
+the C++ Standard Library. This module falls far, far short of providing a
+complete C++ Standard Library and should only be used in dire situations where
+you happen to be compiling with C++17 but don't have a C++ Standard Library
+available to you.
+
+The C++ Standard Library headers (e.g. ``<cstdint>`` and ``<type_traits>``) are
+defined in ``public/``. These files are symlinks to their implementations in
+``public/internal/``.
+
+.. tip::
+
+  You can automatically recreate the symlinks in ``public/`` by executing the
+  following Bash code from ``pw_minimal_cpp_stdlib/public/``.
+
+  .. code-block:: bash
+
+    for f in $(ls internal/); do ln -s internal/$f ${f%.h}; done
+
+Requirments
+===========
+- C++17
+- gcc or clang
+- The C Standard Library
diff --git a/pw_minimal_cpp_stdlib/public/algorithm b/pw_minimal_cpp_stdlib/public/algorithm
new file mode 120000
index 0000000..81f8692
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/algorithm
@@ -0,0 +1 @@
+internal/algorithm.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/array b/pw_minimal_cpp_stdlib/public/array
new file mode 120000
index 0000000..e9f7bca
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/array
@@ -0,0 +1 @@
+internal/array.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/cinttypes b/pw_minimal_cpp_stdlib/public/cinttypes
new file mode 120000
index 0000000..8b251e5
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/cinttypes
@@ -0,0 +1 @@
+internal/cinttypes.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/cmath b/pw_minimal_cpp_stdlib/public/cmath
new file mode 120000
index 0000000..caf5054
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/cmath
@@ -0,0 +1 @@
+internal/cmath.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/cstdarg b/pw_minimal_cpp_stdlib/public/cstdarg
new file mode 120000
index 0000000..5d649b5
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/cstdarg
@@ -0,0 +1 @@
+internal/cstdarg.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/cstddef b/pw_minimal_cpp_stdlib/public/cstddef
new file mode 120000
index 0000000..c351114
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/cstddef
@@ -0,0 +1 @@
+internal/cstddef.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/cstdint b/pw_minimal_cpp_stdlib/public/cstdint
new file mode 120000
index 0000000..749150f
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/cstdint
@@ -0,0 +1 @@
+internal/cstdint.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/cstdio b/pw_minimal_cpp_stdlib/public/cstdio
new file mode 120000
index 0000000..12ae705
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/cstdio
@@ -0,0 +1 @@
+internal/cstdio.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/cstring b/pw_minimal_cpp_stdlib/public/cstring
new file mode 120000
index 0000000..429e026
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/cstring
@@ -0,0 +1 @@
+internal/cstring.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/internal/algorithm.h b/pw_minimal_cpp_stdlib/public/internal/algorithm.h
new file mode 100644
index 0000000..2556702
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/algorithm.h
@@ -0,0 +1,40 @@
+// 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 <type_traits>
+
+namespace std {
+
+template <typename T>
+constexpr const T& min(const T& lhs, const T& rhs) {
+  return (rhs < lhs) ? rhs : lhs;
+}
+
+template <typename T>
+constexpr const T& max(const T& lhs, const T& rhs) {
+  return (lhs < rhs) ? rhs : lhs;
+}
+
+template <typename T>
+constexpr T&& forward(remove_reference_t<T>& value) {
+  return static_cast<T&&>(value);
+}
+
+template <typename T>
+constexpr T&& forward(remove_reference_t<T>&& value) {
+  return static_cast<T&&>(value);
+}
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/array.h b/pw_minimal_cpp_stdlib/public/internal/array.h
new file mode 100644
index 0000000..80aeeca
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/array.h
@@ -0,0 +1,103 @@
+// 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 <iterator>
+
+namespace std {
+
+template <typename T, decltype(sizeof(0)) kSize>
+struct array {
+  using value_type = T;
+  using size_type = decltype(kSize);
+  using difference_type =
+      decltype(static_cast<int*>(nullptr) - static_cast<int*>(nullptr));
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using pointer = value_type*;
+  using const_pointer = const value_type*;
+  using iterator = T*;
+  using const_iterator = const T*;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+  // NOT IMPLEMENTED: at() does not bounds checking.
+  constexpr reference at(size_type index) { return data()[index]; }
+  constexpr const_reference at(size_type index) const { return data()[index]; }
+
+  constexpr reference operator[](size_type index) { return data()[index]; }
+  constexpr const_reference operator[](size_type index) const {
+    return data()[index];
+  }
+
+  constexpr reference front() { return data()[0]; }
+  constexpr const_reference front() const { return data()[0]; }
+
+  constexpr reference back() {
+    static_assert(kSize > 0);
+    return data()[size() - 1];
+  }
+  constexpr const_reference back() const {
+    static_assert(kSize > 0);
+    return data()[size() - 1];
+  }
+
+  constexpr pointer data() noexcept {
+    static_assert(kSize > 0);
+    return __data;
+  }
+  constexpr const_pointer data() const noexcept {
+    static_assert(kSize > 0);
+    return __data;
+  }
+
+  constexpr iterator begin() noexcept { return data(); }
+  constexpr const_iterator begin() const noexcept { return data(); }
+  constexpr const_iterator cbegin() const noexcept { return begin(); }
+
+  constexpr iterator end() noexcept { return data() + kSize; }
+  constexpr const_iterator end() const noexcept { return data() + kSize; }
+  constexpr const_iterator cend() const noexcept { return end(); }
+
+  // NOT IMPLEMENTED
+  constexpr reverse_iterator rbegin() noexcept;
+  constexpr const_reverse_iterator rbegin() const noexcept;
+  constexpr const_reverse_iterator crbegin() const noexcept;
+
+  // NOT IMPLEMENTED
+  constexpr reverse_iterator rend() noexcept;
+  constexpr const_reverse_iterator rend() const noexcept;
+  constexpr const_reverse_iterator crend() const noexcept;
+
+  [[nodiscard]] constexpr bool empty() const noexcept { return kSize == 0u; }
+
+  constexpr size_type size() const noexcept { return kSize; }
+
+  constexpr size_type max_size() const noexcept { return size(); }
+
+  constexpr void fill(const T& value) {
+    for (T& array_value : __data) {
+      array_value = value;
+    }
+  }
+
+  // NOT IMPLEMENTED
+  constexpr void swap(array& other) noexcept;
+
+  T __data[kSize];
+};
+
+// NOT IMPLEMENTED: comparison operators, get, swap, tuple specializations
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/cinttypes.h b/pw_minimal_cpp_stdlib/public/internal/cinttypes.h
new file mode 100644
index 0000000..5141862
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/cinttypes.h
@@ -0,0 +1,16 @@
+// 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 "inttypes.h"
diff --git a/pw_minimal_cpp_stdlib/public/internal/cmath.h b/pw_minimal_cpp_stdlib/public/internal/cmath.h
new file mode 100644
index 0000000..cec4a7e
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/cmath.h
@@ -0,0 +1,55 @@
+// 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 <math.h>
+
+namespace std {
+
+// The integer overloads of these functions are not provided.
+
+// This is not technically correct, but avoids ambiguous calls to an overloaded
+// abs function.
+template <typename T>
+inline T abs(T value) {
+  return value < 0 ? -value : value;
+}
+
+#ifdef isfinite
+#undef isfinite
+#endif  // isfinite
+
+inline bool isfinite(float value) { return __builtin_isfinite(value); }
+inline bool isfinite(double value) { return __builtin_isfinite(value); }
+inline bool isfinite(long double value) { return __builtin_isfinite(value); }
+
+#ifdef isnan
+#undef isnan
+#endif  // isnan
+
+inline bool isnan(float value) { return __builtin_isnan(value); }
+inline bool isnan(double value) { return __builtin_isnan(value); }
+inline bool isnan(long double value) { return __builtin_isnan(value); }
+
+#ifdef signbit
+#undef signbit
+#endif  // signbit
+
+inline bool signbit(float value) { return __builtin_signbit(value); }
+inline bool signbit(double value) { return __builtin_signbit(value); }
+inline bool signbit(long double value) { return __builtin_signbit(value); }
+
+using ::round;
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/cstdarg.h b/pw_minimal_cpp_stdlib/public/internal/cstdarg.h
new file mode 100644
index 0000000..8d31c67
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/cstdarg.h
@@ -0,0 +1,22 @@
+// 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 <stdarg.h>
+
+namespace std {
+
+using ::va_list;
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/cstddef.h b/pw_minimal_cpp_stdlib/public/internal/cstddef.h
new file mode 100644
index 0000000..bcb7bb2
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/cstddef.h
@@ -0,0 +1,74 @@
+// 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 <stddef.h>
+
+namespace std {
+
+using ::ptrdiff_t;
+using ::size_t;
+using nullptr_t = decltype(nullptr);
+using ::max_align_t;
+
+#define __cpp_lib_byte 201603L
+
+enum class byte : unsigned char {};
+
+template <typename I>
+constexpr I to_integer(byte b) noexcept {
+  return I(b);
+}
+
+constexpr byte operator|(byte l, byte r) noexcept {
+  return byte(static_cast<unsigned int>(l) | static_cast<unsigned int>(r));
+}
+
+constexpr byte operator&(byte l, byte r) noexcept {
+  return byte(static_cast<unsigned int>(l) & static_cast<unsigned int>(r));
+}
+
+constexpr byte operator^(byte l, byte r) noexcept {
+  return byte(static_cast<unsigned int>(l) ^ static_cast<unsigned int>(r));
+}
+
+constexpr byte operator~(byte b) noexcept {
+  return byte(~static_cast<unsigned int>(b));
+}
+
+template <typename I>
+constexpr byte operator<<(byte b, I shift) noexcept {
+  return byte(static_cast<unsigned int>(b) << shift);
+}
+
+template <typename I>
+constexpr byte operator>>(byte b, I shift) noexcept {
+  return byte(static_cast<unsigned int>(b) >> shift);
+}
+
+constexpr byte& operator|=(byte& l, byte r) noexcept { return l = l | r; }
+constexpr byte& operator&=(byte& l, byte r) noexcept { return l = l & r; }
+constexpr byte& operator^=(byte& l, byte r) noexcept { return l = l ^ r; }
+
+template <typename I>
+inline byte& operator<<=(byte& b, I shift) noexcept {
+  return b = b << shift;
+}
+
+template <typename I>
+inline byte& operator>>=(byte& b, I shift) noexcept {
+  return b = b >> shift;
+}
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/cstdint.h b/pw_minimal_cpp_stdlib/public/internal/cstdint.h
new file mode 100644
index 0000000..abe9e04
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/cstdint.h
@@ -0,0 +1,16 @@
+// 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 "stdint.h"
diff --git a/pw_minimal_cpp_stdlib/public/internal/cstdio.h b/pw_minimal_cpp_stdlib/public/internal/cstdio.h
new file mode 100644
index 0000000..0a4bae6
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/cstdio.h
@@ -0,0 +1,32 @@
+// 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 <stdio.h>
+
+namespace std {
+
+using ::size_t;
+
+// Only a small subset of functions are exposed here.
+
+using ::putchar;
+using ::puts;
+using ::snprintf;
+using ::vsnprintf;
+
+using ::getchar;
+using ::sscanf;
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/cstring.h b/pw_minimal_cpp_stdlib/public/internal/cstring.h
new file mode 100644
index 0000000..b2f08ad
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/cstring.h
@@ -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.
+#pragma once
+
+#include <string.h>
+
+namespace std {
+
+using ::size_t;
+
+// Only a small subset of functions are exposed here.
+
+using ::memchr;
+using ::memcmp;
+using ::memcpy;
+using ::memmove;
+using ::memset;
+
+using ::strcat;
+using ::strcpy;
+using ::strncat;
+using ::strncpy;
+
+using ::strcmp;
+using ::strlen;
+using ::strncmp;
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/iterator.h b/pw_minimal_cpp_stdlib/public/internal/iterator.h
new file mode 100644
index 0000000..9c5e9ad
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/iterator.h
@@ -0,0 +1,51 @@
+// 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 <cstddef>
+
+namespace std {
+
+#define __cpp_lib_nonmember_container_access 201411L
+
+template <typename C>
+constexpr auto data(C& container) -> decltype(container.data()) {
+  return container.data();
+}
+
+template <typename C>
+constexpr auto data(const C& container) -> decltype(container.data()) {
+  return container.data();
+}
+
+template <typename T, decltype(sizeof(int)) kSize>
+constexpr T* data(T (&array)[kSize]) noexcept {
+  return array;
+}
+
+template <typename C>
+constexpr auto size(const C& container) -> decltype(container.size()) {
+  return container.size();
+}
+
+template <typename T, decltype(sizeof(int)) kSize>
+constexpr decltype(sizeof(int)) size(const T (&)[kSize]) noexcept {
+  return kSize;
+}
+
+// NOT IMPLEMENTED: Reverse iterators are not implemented.
+template <typename>
+struct reverse_iterator;
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/limits.h b/pw_minimal_cpp_stdlib/public/internal/limits.h
new file mode 100644
index 0000000..6c14180
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/limits.h
@@ -0,0 +1,65 @@
+// 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 <limits.h>
+
+namespace std {
+
+template <typename T>
+struct numeric_limits {
+  static constexpr bool is_specialized = false;
+};
+
+// Only a few of the numeric_limits methods are implemented.
+#define _PW_LIMITS_SPECIALIZATION(                               \
+    type, val_signed, val_int, min_value, max_value)             \
+  template <>                                                    \
+  struct numeric_limits<type> {                                  \
+    static constexpr bool is_specialized = true;                 \
+                                                                 \
+    static constexpr bool is_signed = (val_signed);              \
+    static constexpr bool is_integer = (val_int);                \
+                                                                 \
+    static constexpr type min() noexcept { return (min_value); } \
+    static constexpr type max() noexcept { return (max_value); } \
+  }
+
+#define _PW_INTEGRAL_LIMIT(type, sname, uname)            \
+  _PW_LIMITS_SPECIALIZATION(                              \
+      signed type, true, true, sname##_MIN, sname##_MAX); \
+  _PW_LIMITS_SPECIALIZATION(unsigned type, false, true, 0u, uname##_MAX)
+
+_PW_LIMITS_SPECIALIZATION(bool, false, true, false, true);
+_PW_LIMITS_SPECIALIZATION(char, char(-1) < char(0), true, CHAR_MIN, CHAR_MAX);
+
+_PW_INTEGRAL_LIMIT(char, SCHAR, UCHAR);
+_PW_INTEGRAL_LIMIT(short, SHRT, USHRT);
+_PW_INTEGRAL_LIMIT(int, INT, UINT);
+_PW_INTEGRAL_LIMIT(long, LONG, ULONG);
+
+#ifndef LLONG_MIN
+#define LLONG_MIN ((long long)(~0ull ^ (~0ull >> 1)))
+#define LLONG_MAX ((long long)(~0ull >> 1))
+
+#define ULLONG_MIN (0ull)
+#define ULLONG_MAX (~0ull)
+#endif  // LLONG_MIN
+
+_PW_INTEGRAL_LIMIT(long long, LLONG, ULLONG);
+
+#undef _PW_LIMITS_SPECIALIZATION
+#undef _PW_INTEGRAL_LIMIT
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/new.h b/pw_minimal_cpp_stdlib/public/internal/new.h
new file mode 100644
index 0000000..d21d991
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/new.h
@@ -0,0 +1,17 @@
+// 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
+
+// Placement new
+inline void* operator new(decltype(sizeof(0)), void* ptr) { return ptr; }
diff --git a/pw_minimal_cpp_stdlib/public/internal/string_view.h b/pw_minimal_cpp_stdlib/public/internal/string_view.h
new file mode 100644
index 0000000..65ee858
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/string_view.h
@@ -0,0 +1,174 @@
+// 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 <iterator>
+
+#define __cpp_lib_string_view 201606L
+
+namespace std {
+
+template <typename T>
+class basic_string_view {
+ public:
+  using traits_type = void;  // No traits object is used.
+  using value_type = T;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using reference = T&;
+  using const_reference = const T&;
+  using const_iterator = const T*;
+  using iterator = const_iterator;
+  using const_reverse_iterator = ::std::reverse_iterator<const_iterator>;
+  using reverse_iterator = const_reverse_iterator;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+
+  static constexpr size_type npos = size_type(-1);
+
+  constexpr basic_string_view() noexcept : string_(nullptr), size_(0) {}
+  constexpr basic_string_view(const basic_string_view&) noexcept = default;
+  constexpr basic_string_view(const T* string, size_type count)
+      : string_(string), size_(count) {}
+  constexpr basic_string_view(const T* string)
+      : string_(string), size_(CStringLength(string)) {}
+
+  constexpr basic_string_view& operator=(const basic_string_view&) noexcept =
+      default;
+
+  constexpr const_iterator begin() const noexcept { return string_; }
+  constexpr const_iterator cbegin() const noexcept { return begin(); }
+
+  constexpr const_iterator end() const noexcept { return string_ + size_; }
+  constexpr const_iterator cend() const noexcept { return end(); }
+
+  // NOT IMPLEMENTED: Reverse iterators not supported.
+  constexpr const_reverse_iterator rbegin() const noexcept;
+  constexpr const_reverse_iterator crbegin() const noexcept;
+
+  constexpr const_reverse_iterator rend() const noexcept;
+  constexpr const_reverse_iterator crend() const noexcept;
+
+  constexpr const_reference operator[](size_type pos) const {
+    return data()[pos];
+  }
+
+  // NOT IMPLEMENTED: at() has no bounds checking.
+  constexpr const_reference at(size_type pos) const { return data()[pos]; }
+
+  constexpr const_reference front() const { return data()[0]; }
+
+  constexpr const_reference back() const { return data()[size() - 1]; }
+
+  constexpr const_pointer data() const noexcept { return string_; }
+
+  constexpr size_type size() const noexcept { return size_; }
+  constexpr size_type length() const noexcept { return size(); }
+
+  constexpr size_type max_size() const noexcept { return ~size_t{0}; }
+
+  [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0u; }
+
+  constexpr void remove_prefix(size_type characters) {
+    string_ += characters;
+    size_ -= characters;
+  }
+
+  constexpr void remove_suffix(size_type characters) { size_ -= characters; }
+
+  constexpr void swap(basic_string_view& other) noexcept {
+    pointer temp_string = string_;
+    string_ = other.string_;
+    other.string_ = temp_string;
+
+    size_type temp_size = size_;
+    size_ = other.size_;
+    other.size_ = temp_size;
+  }
+
+  // NOT IMPLEMENTED: copy does no bounds checking.
+  constexpr size_type copy(T* dest, size_type count, size_type pos = 0) const {
+    const size_type to_copy = min(count, size() - pos);
+    for (size_type i = pos; i < pos + to_copy; ++i) {
+      *dest++ = string_[i];
+    }
+    return to_copy;
+  }
+
+  constexpr basic_string_view substr(size_type pos = 0,
+                                     size_type count = npos) const {
+    return basic_string_view(string_ + pos, min(count, size() - pos));
+  }
+
+  // NOT IMPLEMENTED: These functions and their overloads are not defined.
+  constexpr int compare(basic_string_view view) const noexcept;
+  constexpr bool starts_with(basic_string_view view) const noexcept;
+  constexpr bool ends_with(basic_string_view view) const noexcept;
+  constexpr size_type find(basic_string_view view,
+                           size_type pos = 0) const noexcept;
+  constexpr size_type rfind(basic_string_view view,
+                            size_type pos = npos) const noexcept;
+  constexpr size_type find_first_of(basic_string_view view,
+                                    size_type pos = 0) const noexcept;
+  constexpr size_type find_last_of(basic_string_view view,
+                                   size_type pos = npos) const noexcept;
+  constexpr size_type find_first_not_of(basic_string_view view,
+                                        size_type pos = 0) const noexcept;
+  constexpr size_type find_last_not_of(basic_string_view view,
+                                       size_type pos = npos) const noexcept;
+
+ private:
+  static constexpr size_type CStringLength(const T* string) {
+    size_type length = 0;
+    while (string[length] != T()) {
+      length += 1;
+    }
+    return length;
+  }
+
+  const_pointer string_;
+  size_type size_;
+};
+
+template <typename T>
+constexpr bool operator==(basic_string_view<T> lhs, basic_string_view<T> rhs) {
+  if (lhs.size() != rhs.size()) {
+    return false;
+  }
+  for (typename basic_string_view<T>::size_type i = 0; i < lhs.size(); ++i) {
+    if (lhs[i] != rhs[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <typename T>
+constexpr bool operator!=(basic_string_view<T> lhs, basic_string_view<T> rhs) {
+  return !(lhs == rhs);
+}
+
+// NOT IMPLEMENTED: Other comparison operators are not defined.
+
+using string_view = basic_string_view<char>;
+using wstring_view = basic_string_view<wchar_t>;
+using u16string_view = basic_string_view<char16_t>;
+using u32string_view = basic_string_view<char32_t>;
+
+// NOT IMPLEMENTED: string_view literals cannot be implemented since they do not
+//                  start with _.
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/type_traits.h b/pw_minimal_cpp_stdlib/public/internal/type_traits.h
new file mode 100644
index 0000000..422b2df
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/type_traits.h
@@ -0,0 +1,425 @@
+// 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
+
+namespace std {
+
+#define __cpp_lib_transformation_trait_aliases 201304L
+#define __cpp_lib_type_trait_variable_templates 201510L
+
+template <decltype(sizeof(0)) kLength,
+          decltype(sizeof(0)) kAlignment>  // no default
+struct aligned_storage {
+  struct type {
+    alignas(kAlignment) unsigned char __data[kLength];
+  };
+};
+
+template <decltype(sizeof(0)) kLength,
+          decltype(sizeof(0)) kAlignment>  // no default
+using aligned_storage_t = typename aligned_storage<kLength, kAlignment>::type;
+
+#define __cpp_lib_integral_constant_callable 201304L
+
+template <typename T, T kValue>
+struct integral_constant {
+  using value_type = T;
+  using type = integral_constant;
+
+  static constexpr T value = kValue;
+
+  constexpr operator value_type() const noexcept { return value; }
+
+  constexpr value_type operator()() const noexcept { return value; }
+};
+
+#define __cpp_lib_bool_constant 201505L
+
+template <bool kValue>
+using bool_constant = integral_constant<bool, kValue>;
+
+using true_type = bool_constant<true>;
+using false_type = bool_constant<false>;
+
+template <typename T>
+struct is_array : false_type {};
+
+template <typename T>
+struct is_array<T[]> : true_type {};
+
+template <typename T, decltype(sizeof(int)) kSize>
+struct is_array<T[kSize]> : true_type {};
+
+template <typename T>
+inline constexpr bool is_array_v = is_array<T>::value;
+
+template <typename T>
+struct is_const : false_type {};
+
+template <typename T>
+struct is_const<const T> : true_type {};
+
+// NOT IMPLEMENTED: is_enum requires compiler builtins.
+template <typename T>
+struct is_enum : false_type {};
+
+template <typename T>
+inline constexpr bool is_enum_v = is_enum<T>::value;
+
+template <typename T>
+struct remove_cv;  // Forward declaration
+
+namespace impl {
+
+template <typename T>
+struct is_floating_point : false_type {};
+
+template <>
+struct is_floating_point<float> : true_type {};
+template <>
+struct is_floating_point<double> : true_type {};
+template <>
+struct is_floating_point<long double> : true_type {};
+
+}  // namespace impl
+
+template <typename T>
+struct is_floating_point
+    : impl::is_floating_point<typename remove_cv<T>::type> {};
+
+template <typename T>
+inline constexpr bool is_floating_point_v = is_floating_point<T>::value;
+
+namespace impl {
+
+template <typename T>
+struct is_integral : false_type {};
+
+template <>
+struct is_integral<bool> : true_type {};
+template <>
+struct is_integral<char> : true_type {};
+template <>
+struct is_integral<char16_t> : true_type {};
+template <>
+struct is_integral<char32_t> : true_type {};
+template <>
+struct is_integral<wchar_t> : true_type {};
+
+template <>
+struct is_integral<short> : true_type {};
+template <>
+struct is_integral<unsigned short> : true_type {};
+template <>
+struct is_integral<int> : true_type {};
+template <>
+struct is_integral<unsigned int> : true_type {};
+template <>
+struct is_integral<long> : true_type {};
+template <>
+struct is_integral<unsigned long> : true_type {};
+template <>
+struct is_integral<long long> : true_type {};
+template <>
+struct is_integral<unsigned long long> : true_type {};
+
+}  // namespace impl
+
+template <typename T>
+struct is_integral : impl::is_integral<typename remove_cv<T>::type> {};
+
+template <typename T>
+inline constexpr bool is_integral_v = is_integral<T>::value;
+
+template <typename T>
+struct is_arithmetic
+    : bool_constant<is_integral_v<T> || is_floating_point_v<T>> {};
+
+template <typename T>
+inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
+
+#define __cpp_lib_is_null_pointer 201309L
+
+template <typename T>
+struct is_null_pointer : false_type {};
+
+template <>
+struct is_null_pointer<decltype(nullptr)> : true_type {};
+
+template <typename T>
+inline constexpr bool is_null_pointer_v = is_null_pointer<T>::value;
+
+template <typename T>
+struct is_pointer : false_type {};
+
+template <typename T>
+struct is_pointer<T*> : true_type {};
+
+template <typename T>
+inline constexpr bool is_pointer_v = is_pointer<T>::value;
+
+template <typename T, typename U>
+struct is_same : false_type {};
+
+template <typename T>
+struct is_same<T, T> : true_type {};
+
+template <typename T, typename U>
+inline constexpr bool is_same_v = is_same<T, U>::value;
+
+namespace impl {
+
+template <typename T, bool = is_arithmetic<T>::value>
+struct is_signed : integral_constant<bool, T(-1) < T(0)> {};
+
+template <typename T>
+struct is_signed<T, false> : false_type {};
+
+}  // namespace impl
+
+template <typename T>
+struct is_signed : impl::is_signed<T>::type {};
+
+template <typename T>
+inline constexpr bool is_signed_v = is_signed<T>::value;
+
+template <typename T>
+struct is_unsigned : bool_constant<!is_signed_v<T>> {};
+
+template <typename T>
+inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
+
+template <typename T>
+struct is_void : is_same<void, typename remove_cv<T>::type> {};
+
+template <typename T>
+inline constexpr bool is_void_v = is_void<T>::value;
+
+template <bool kBool, typename TrueType, typename FalseType>
+struct conditional {
+  using type = TrueType;
+};
+
+template <typename TrueType, typename FalseType>
+struct conditional<false, TrueType, FalseType> {
+  using type = FalseType;
+};
+
+template <bool kBool, typename TrueType, typename FalseType>
+using conditional_t = typename conditional<kBool, TrueType, FalseType>::type;
+
+template <bool kEnable, typename T = void>
+struct enable_if {
+  using type = T;
+};
+
+template <typename T>
+struct enable_if<false, T> {};
+
+template <bool kEnable, typename T = void>
+using enable_if_t = typename enable_if<kEnable, T>::type;
+
+template <typename T>
+struct remove_const {
+  using type = T;
+};
+
+template <typename T>
+struct remove_const<const T> {
+  using type = T;
+};
+
+template <typename T>
+using remove_const_t = typename remove_const<T>::type;
+
+template <typename T>
+struct remove_volatile {
+  using type = T;
+};
+
+template <typename T>
+struct remove_volatile<volatile T> {
+  using type = T;
+};
+
+template <typename T>
+using remove_volatile_t = typename remove_volatile<T>::type;
+
+template <typename T>
+struct remove_cv {
+  using type = remove_volatile_t<remove_const_t<T>>;
+};
+
+template <typename T>
+using remove_cv_t = typename remove_cv<T>::type;
+
+template <typename T>
+struct remove_extent {
+  using type = T;
+};
+
+template <typename T>
+struct remove_extent<T[]> {
+  using type = T;
+};
+
+template <typename T, decltype(sizeof(0)) kSize>
+struct remove_extent<T[kSize]> {
+  using type = T;
+};
+
+template <typename T>
+using remove_extent_t = typename remove_extent<T>::type;
+
+template <typename T>
+struct remove_pointer {
+  using type = T;
+};
+
+template <typename T>
+struct remove_pointer<T*> {
+  using type = T;
+};
+
+template <typename T>
+struct remove_pointer<T* const> {
+  using type = T;
+};
+
+template <typename T>
+struct remove_pointer<T* volatile> {
+  using type = T;
+};
+
+template <typename T>
+struct remove_pointer<T* const volatile> {
+  using type = T;
+};
+
+template <typename T>
+using remove_pointer_t = typename remove_pointer<T>::type;
+
+template <typename T>
+struct remove_reference {
+  using type = T;
+};
+
+template <typename T>
+struct remove_reference<T&> {
+  using type = T;
+};
+
+template <typename T>
+struct remove_reference<T&&> {
+  using type = T;
+};
+
+template <typename T>
+using remove_reference_t = typename remove_reference<T>::type;
+
+// NOT IMPLEMENTED: This implementation is INCOMPLETE, as it does not cover
+// function types.
+template <typename T>
+struct decay {
+ private:
+  using U = remove_reference_t<T>;
+
+ public:
+  using type =
+      conditional_t<is_array<U>::value, remove_extent_t<U>*, remove_cv_t<U>>;
+};
+
+template <typename T>
+using decay_t = typename decay<T>::type;
+
+#define __cpp_lib_type_identity 201806
+
+template <class T>
+struct type_identity {
+  using type = T;
+};
+
+template <typename T>
+using type_identity_t = typename type_identity<T>::type;
+
+#define __cpp_lib_void_t void_t 201411L
+
+template <typename...>
+using void_t = void;
+
+// NOT IMPLEMENTED: add_rvalue_refernce does work with reference types.
+template <typename T>
+struct add_rvalue_reference {
+  using type = T&&;
+};
+
+template <typename T>
+using add_rvalue_reference_t = typename add_rvalue_reference<T>::type;
+
+template <typename T>
+add_rvalue_reference_t<T> declval() noexcept;
+
+namespace impl {
+
+template <typename>
+using templated_true = true_type;
+
+template <typename T>
+auto returnable(int) -> templated_true<T()>;
+
+template <typename>
+auto returnable(...) -> false_type;
+
+template <typename From, typename To>
+auto convertible(int)
+    -> templated_true<decltype(declval<void (&)(To)>()(declval<From>()))>;
+
+template <typename, typename>
+auto convertible(...) -> false_type;
+
+}  // namespace impl
+
+template <typename From, typename To>
+struct is_convertible
+    : bool_constant<(decltype(impl::returnable<To>(0))() &&
+                     decltype(impl::convertible<From, To>(0))()) ||
+                    (is_void_v<From> && is_void_v<To>)> {};
+
+template <typename T, typename U>
+inline constexpr bool is_convertible_v = is_convertible<T, U>::value;
+
+// NOT IMPLEMENTED: Stubs are provided for these traits classes, but they do not
+// return useful values. Many of these would require compiler builtins.
+template <typename T>
+struct is_function : false_type {};
+template <typename T>
+struct is_trivially_copyable : true_type {};
+template <typename T>
+struct is_polymorphic : false_type {};
+template <typename T, typename U>
+struct is_base_of : false_type {};
+template <typename T>
+struct extent : integral_constant<decltype(sizeof(int)), 1> {};
+template <typename T>
+inline constexpr bool extent_v = extent<T>::value;
+template <typename T>
+struct underlying_type {
+  using type = T;
+};
+template <typename T>
+using underlying_type_t = typename underlying_type<T>::type;
+template <typename T>
+inline constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/internal/utility.h b/pw_minimal_cpp_stdlib/public/internal/utility.h
new file mode 100644
index 0000000..6d238f7
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/utility.h
@@ -0,0 +1,25 @@
+// 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
+
+namespace std {
+
+// Forward declare these classes, which are specialized in other headers.
+template <decltype(sizeof(0)), typename>
+struct tuple_element;
+
+template <typename>
+struct tuple_size;
+
+}  // namespace std
diff --git a/pw_minimal_cpp_stdlib/public/iterator b/pw_minimal_cpp_stdlib/public/iterator
new file mode 120000
index 0000000..4703aa8
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/iterator
@@ -0,0 +1 @@
+internal/iterator.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/limits b/pw_minimal_cpp_stdlib/public/limits
new file mode 120000
index 0000000..8309de0
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/limits
@@ -0,0 +1 @@
+internal/limits.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/new b/pw_minimal_cpp_stdlib/public/new
new file mode 120000
index 0000000..ed0129c
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/new
@@ -0,0 +1 @@
+internal/new.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/string_view b/pw_minimal_cpp_stdlib/public/string_view
new file mode 120000
index 0000000..8e1be67
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/string_view
@@ -0,0 +1 @@
+internal/string_view.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/type_traits b/pw_minimal_cpp_stdlib/public/type_traits
new file mode 120000
index 0000000..71b1217
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/type_traits
@@ -0,0 +1 @@
+internal/type_traits.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/public/utility b/pw_minimal_cpp_stdlib/public/utility
new file mode 120000
index 0000000..58c32f2
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/utility
@@ -0,0 +1 @@
+internal/utility.h
\ No newline at end of file
diff --git a/pw_minimal_cpp_stdlib/test.cc b/pw_minimal_cpp_stdlib/test.cc
new file mode 100644
index 0000000..1d9c6c3
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/test.cc
@@ -0,0 +1,151 @@
+// 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.
+
+// Include all of the provided headers, even if they aren't tested.
+#include <algorithm>
+#include <array>
+#include <cinttypes>
+#include <cmath>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <new>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(Algorithm, Basic) {
+  static_assert(std::min(1, 2) == 1);
+  static_assert(std::max(1, 2) == 2);
+
+  EXPECT_EQ(std::forward<int>(2), 2);
+}
+
+TEST(Array, Basic) {
+  constexpr std::array<int, 4> array{0, 1, 2, 3};
+
+  static_assert(array[2] == 2);
+
+  for (int i = 0; i < static_cast<int>(array.size()); ++i) {
+    EXPECT_EQ(i, array[i]);
+  }
+}
+
+TEST(Cmath, Basic) {
+  EXPECT_EQ(std::abs(-1), 1);
+  EXPECT_EQ(std::abs(1), 1);
+
+  EXPECT_TRUE(std::isfinite(1.0));
+  EXPECT_FALSE(std::isfinite(1.0 / 0.0));
+
+  EXPECT_FALSE(std::isnan(1.0));
+  EXPECT_TRUE(std::isnan(0.0 / 0.0));
+
+  EXPECT_FALSE(std::signbit(1.0));
+  EXPECT_TRUE(std::signbit(-1.0));
+}
+
+TEST(Cstddef, Basic) {
+  using std::byte;
+  byte foo = byte{12};
+  EXPECT_EQ(foo, byte{12});
+}
+
+TEST(Iterator, Basic) {
+  std::array<int, 3> foo{3, 2, 1};
+
+  EXPECT_EQ(std::data(foo), foo.data());
+  EXPECT_EQ(std::size(foo), foo.size());
+
+  foo.fill(99);
+  EXPECT_EQ(foo[0], 99);
+  EXPECT_EQ(foo[1], 99);
+  EXPECT_EQ(foo[2], 99);
+}
+
+TEST(Limits, Basic) {
+  static_assert(std::numeric_limits<unsigned char>::is_specialized);
+  static_assert(std::numeric_limits<unsigned char>::is_integer);
+  static_assert(std::numeric_limits<unsigned char>::min() == 0u);
+  static_assert(std::numeric_limits<unsigned char>::max() == 255u);
+
+  static_assert(std::numeric_limits<signed char>::is_specialized);
+  static_assert(std::numeric_limits<signed char>::is_integer);
+  static_assert(std::numeric_limits<signed char>::min() == -128);
+  static_assert(std::numeric_limits<signed char>::max() == 127);
+
+  // Assume 64-bit long long
+  static_assert(std::numeric_limits<long long>::is_specialized);
+  static_assert(std::numeric_limits<long long>::is_integer);
+  static_assert(std::numeric_limits<long long>::min() ==
+                (-9223372036854775807ll - 1));
+  static_assert(std::numeric_limits<long long>::max() == 9223372036854775807ll);
+
+  static_assert(std::numeric_limits<unsigned long long>::is_specialized);
+  static_assert(std::numeric_limits<unsigned long long>::is_integer);
+  static_assert(std::numeric_limits<unsigned long long>::min() == 0u);
+  static_assert(std::numeric_limits<unsigned long long>::max() ==
+                18446744073709551615ull);
+}
+
+TEST(New, Basic) {
+  unsigned char value[4];
+  new (value) int(1234);
+
+  int int_value;
+  std::memcpy(&int_value, value, sizeof(int_value));
+  EXPECT_EQ(1234, int_value);
+}
+
+TEST(StringView, Basic) {
+  constexpr std::string_view value("1234567890");
+  static_assert(value.size() == 10);
+  static_assert(value[1] == '2');
+
+  char buffer[] = "!!!!!";
+  constexpr size_t buffer_size = sizeof(buffer) - 1;  // always keep the \0
+
+  value.copy(buffer, buffer_size, 10);
+  EXPECT_STREQ(buffer, "!!!!!");
+
+  value.copy(buffer, buffer_size, 9);
+  EXPECT_STREQ(buffer, "0!!!!");
+
+  value.copy(buffer, buffer_size, 2);
+  EXPECT_STREQ(buffer, "34567");
+
+  value.copy(buffer, buffer_size);
+  EXPECT_STREQ(buffer, "12345");
+}
+
+TEST(TypeTraits, Basic) {
+  static_assert(std::is_integral_v<bool>);
+  static_assert(!std::is_integral_v<float>);
+
+  static_assert(std::is_floating_point_v<float>);
+  static_assert(!std::is_floating_point_v<bool>);
+
+  static_assert(std::is_same_v<float, float>);
+  static_assert(!std::is_same_v<char, unsigned char>);
+}
+
+}  // namespace