pw_minimal_cpp_stdlib: More iterator support
Update pw_minimal_cpp_stdlib to include the following:
- climits header
- std::begin() and std::end()
- std::find()
- std::copy()
Change-Id: Iac5818e897daf79ff0a4c882a5a730da8e84a3f8
diff --git a/pw_minimal_cpp_stdlib/BUILD b/pw_minimal_cpp_stdlib/BUILD
index 592cab7..96aca6d 100644
--- a/pw_minimal_cpp_stdlib/BUILD
+++ b/pw_minimal_cpp_stdlib/BUILD
@@ -28,6 +28,7 @@
"public/internal/algorithm.h",
"public/internal/array.h",
"public/internal/cinttypes.h",
+ "public/internal/climits.h",
"public/internal/cmath.h",
"public/internal/cstdarg.h",
"public/internal/cstddef.h",
@@ -46,6 +47,7 @@
"public/algorithm",
"public/array",
"public/cinttypes",
+ "public/climits",
"public/cmath",
"public/cstdarg",
"public/cstddef",
diff --git a/pw_minimal_cpp_stdlib/BUILD.gn b/pw_minimal_cpp_stdlib/BUILD.gn
index 97060a5..3cbe163 100644
--- a/pw_minimal_cpp_stdlib/BUILD.gn
+++ b/pw_minimal_cpp_stdlib/BUILD.gn
@@ -30,6 +30,7 @@
"public/algorithm",
"public/array",
"public/cinttypes",
+ "public/climits",
"public/cmath",
"public/cstdarg",
"public/cstddef",
@@ -48,6 +49,7 @@
"public/internal/algorithm.h",
"public/internal/array.h",
"public/internal/cinttypes.h",
+ "public/internal/climits.h",
"public/internal/cmath.h",
"public/internal/cstdarg.h",
"public/internal/cstddef.h",
diff --git a/pw_minimal_cpp_stdlib/public/climits b/pw_minimal_cpp_stdlib/public/climits
new file mode 120000
index 0000000..e098495
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/climits
@@ -0,0 +1 @@
+internal/climits.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
index f905e11..6ad7179 100644
--- a/pw_minimal_cpp_stdlib/public/internal/algorithm.h
+++ b/pw_minimal_cpp_stdlib/public/internal/algorithm.h
@@ -17,6 +17,16 @@
namespace std {
+template <class InputIterator, class OutputIterator>
+constexpr OutputIterator copy(InputIterator first,
+ InputIterator last,
+ OutputIterator dest) {
+ while (first != last) {
+ *dest++ = *first++;
+ }
+ return dest;
+}
+
template <typename T>
constexpr const T& min(const T& lhs, const T& rhs) {
return (rhs < lhs) ? rhs : lhs;
@@ -27,6 +37,18 @@
return (lhs < rhs) ? rhs : lhs;
}
+template <class InputIterator, typename T>
+constexpr InputIterator find(InputIterator first,
+ InputIterator last,
+ const T& value) {
+ for (; first != last; ++first) {
+ if (*first == value) {
+ return first;
+ }
+ }
+ return last;
+}
+
template <typename T>
constexpr T&& forward(remove_reference_t<T>& value) {
return static_cast<T&&>(value);
diff --git a/pw_minimal_cpp_stdlib/public/internal/climits.h b/pw_minimal_cpp_stdlib/public/internal/climits.h
new file mode 100644
index 0000000..6acdaea
--- /dev/null
+++ b/pw_minimal_cpp_stdlib/public/internal/climits.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 <limits.h>
diff --git a/pw_minimal_cpp_stdlib/public/internal/iterator.h b/pw_minimal_cpp_stdlib/public/internal/iterator.h
index 4470731..e3010be 100644
--- a/pw_minimal_cpp_stdlib/public/internal/iterator.h
+++ b/pw_minimal_cpp_stdlib/public/internal/iterator.h
@@ -20,6 +20,16 @@
#define __cpp_lib_nonmember_container_access 201411L
template <typename C>
+auto begin(C& container) -> decltype(container.begin()) {
+ return container.begin();
+}
+
+template <typename C>
+auto begin(const C& container) -> decltype(container.begin()) {
+ return container.begin();
+}
+
+template <typename C>
constexpr auto data(C& container) -> decltype(container.data()) {
return container.data();
}
@@ -35,6 +45,16 @@
}
template <typename C>
+auto end(C& container) -> decltype(container.end()) {
+ return container.end();
+}
+
+template <typename C>
+auto end(const C& container) -> decltype(container.end()) {
+ return container.end();
+}
+
+template <typename C>
constexpr auto size(const C& container) -> decltype(container.size()) {
return container.size();
}
diff --git a/pw_minimal_cpp_stdlib/test.cc b/pw_minimal_cpp_stdlib/test.cc
index a29f649..63129e3 100644
--- a/pw_minimal_cpp_stdlib/test.cc
+++ b/pw_minimal_cpp_stdlib/test.cc
@@ -41,6 +41,64 @@
EXPECT_EQ(std::forward<int>(2), 2);
}
+TEST(Algorithm, Copy) {
+ constexpr size_t kCopyOffset = 1;
+ std::array<int, 3> foo{3, 2, 1};
+ std::array<int, 5> bar{0};
+
+ // Ensure zero-element iterator doesn't modify the destination object when
+ // copied.
+ int temp = foo[0];
+ std::copy(foo.end(), foo.end(), bar.begin());
+ EXPECT_EQ(foo[0], temp);
+
+ // Copy a single element.
+ std::array<int, 1> one{-101};
+ std::copy(one.begin(), one.end(), foo.begin());
+ EXPECT_EQ(foo[0], -101);
+
+ auto copy_end = std::copy(foo.begin(), foo.end(), bar.begin() + kCopyOffset);
+ // Verify the iterator points to the end of the copied region.
+ EXPECT_EQ(copy_end, bar.begin() + foo.size() + kCopyOffset);
+
+ // Verify all the values were properly copied from foo to bar.
+ {
+ size_t i = 0;
+ for (auto it = bar.begin() + kCopyOffset; it != copy_end; ++it) {
+ EXPECT_EQ(*it, foo[i++]);
+ }
+ }
+}
+
+TEST(Algorithm, Find) {
+ std::array<int, 5> foo{3, 2, 1, 42, 17};
+ // Ensure a value in the middle of the array is properly found.
+ EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 42), 42);
+
+ // Ensure the iterator returned by find() matches the expected location of the
+ // element.
+ EXPECT_EQ(std::find(std::begin(foo), std::end(foo), 42), std::begin(foo) + 3);
+
+ // Ensure an element at the beginning of an array is found.
+ EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 3), foo[0]);
+
+ // Ensure an element at the end of an array is found.
+ EXPECT_EQ(*std::find(std::begin(foo), std::end(foo), 17),
+ foo[foo.size() - 1]);
+}
+
+TEST(Algorithm, NotFound) {
+ std::array<int, 3> foo{3, 2, 1};
+
+ // Ensure that if an element is not found, an iterator matching foo.end() is
+ // returned.
+ EXPECT_EQ(std::find(std::begin(foo), std::end(foo), -99), std::end(foo));
+
+ // Ensure that a zero-element iterator range returns the end iterator passed
+ // to std::find().
+ EXPECT_EQ(std::find(std::end(foo), std::end(foo), 3), std::end(foo));
+}
+
TEST(Array, Basic) {
constexpr std::array<int, 4> array{0, 1, 2, 3};
@@ -77,6 +135,9 @@
EXPECT_EQ(std::data(foo), foo.data());
EXPECT_EQ(std::size(foo), foo.size());
+ EXPECT_EQ(*std::begin(foo), foo[0]);
+ EXPECT_EQ(std::end(foo), std::begin(foo) + foo.size());
+
foo.fill(99);
EXPECT_EQ(foo[0], 99);
EXPECT_EQ(foo[1], 99);