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