diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt index 5b89257418732..e11d823333b25 100644 --- a/libc/src/__support/CPP/CMakeLists.txt +++ b/libc/src/__support/CPP/CMakeLists.txt @@ -114,6 +114,9 @@ add_header_library( optional HDRS optional.h + DEPENDS + .type_traits + .utility ) add_header_library( diff --git a/libc/src/__support/CPP/optional.h b/libc/src/__support/CPP/optional.h index aed2269db1b11..3b3153f6f1920 100644 --- a/libc/src/__support/CPP/optional.h +++ b/libc/src/__support/CPP/optional.h @@ -131,6 +131,17 @@ template class optional { LIBC_INLINE constexpr T &&operator*() && { return move(storage.stored_value); } + + template + LIBC_INLINE constexpr T value_or(U &&default_value) const & { + return has_value() ? storage.stored_value + : static_cast(forward(default_value)); + } + + template LIBC_INLINE constexpr T value_or(U &&default_value) && { + return has_value() ? move(storage.stored_value) + : static_cast(forward(default_value)); + } }; } // namespace cpp diff --git a/libc/test/src/__support/CPP/optional_test.cpp b/libc/test/src/__support/CPP/optional_test.cpp index b2c8545eb36f0..4a6ebd8d51d7f 100644 --- a/libc/test/src/__support/CPP/optional_test.cpp +++ b/libc/test/src/__support/CPP/optional_test.cpp @@ -80,3 +80,22 @@ TEST(LlvmLibcOptionalTest, Tests) { ASSERT_EQ(arrow_num, 11); arrow_test.reset(); } + +TEST(LlvmLibcOptionalTest, ValueOr) { + optional opt_empty; + EXPECT_EQ(opt_empty.value_or(42), 42); + optional opt_full(10); + EXPECT_EQ(opt_full.value_or(42), 10); + EXPECT_EQ(optional(100).value_or(42), 100); + EXPECT_EQ(optional().value_or(42), 42); + + const optional opt_const_empty; + EXPECT_EQ(opt_const_empty.value_or(42), 42); + const optional opt_const_full(10); + EXPECT_EQ(opt_const_full.value_or(42), 10); + + optional opt_long_empty; + EXPECT_EQ(opt_long_empty.value_or(42), 42L); + optional opt_long_full(100L); + EXPECT_EQ(opt_long_full.value_or(42), 100L); +} diff --git a/libc/test/src/net/linux/CMakeLists.txt b/libc/test/src/net/linux/CMakeLists.txt index 08f288e2256f6..22f4c2429805e 100644 --- a/libc/test/src/net/linux/CMakeLists.txt +++ b/libc/test/src/net/linux/CMakeLists.txt @@ -38,11 +38,11 @@ add_libc_unittest( libc.hdr.types.socklen_t libc.hdr.types.ssize_t libc.hdr.types.struct_if_nameindex + libc.src.__support.CPP.optional libc.src.__support.CPP.span libc.src.__support.CPP.string libc.src.__support.CPP.string_view libc.src.__support.CPP.tuple - libc.src.__support.CPP.type_traits libc.src.__support.error_or libc.src.__support.fixedvector libc.src.net.if_freenameindex diff --git a/libc/test/src/net/linux/if_nameindex_test.cpp b/libc/test/src/net/linux/if_nameindex_test.cpp index ef5022b6420dc..1285f967ad0b1 100644 --- a/libc/test/src/net/linux/if_nameindex_test.cpp +++ b/libc/test/src/net/linux/if_nameindex_test.cpp @@ -16,11 +16,11 @@ #include "hdr/types/socklen_t.h" #include "hdr/types/ssize_t.h" #include "hdr/types/struct_if_nameindex.h" +#include "src/__support/CPP/optional.h" #include "src/__support/CPP/span.h" #include "src/__support/CPP/string.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/tuple.h" -#include "src/__support/CPP/type_traits/type_identity.h" #include "src/__support/error_or.h" #include "src/__support/fixedvector.h" #include "src/net/if_freenameindex.h" @@ -38,18 +38,17 @@ using LIBC_NAMESPACE::Error; using LIBC_NAMESPACE::ErrorOr; using LIBC_NAMESPACE::FixedVector; using LIBC_NAMESPACE::cpp::get; +using LIBC_NAMESPACE::cpp::nullopt; +using LIBC_NAMESPACE::cpp::optional; using LIBC_NAMESPACE::cpp::span; using LIBC_NAMESPACE::cpp::string; using LIBC_NAMESPACE::cpp::string_view; using LIBC_NAMESPACE::cpp::tuple; -// TODO: Add optional::value_or, then return optional. template -static T -pop_front_or(FixedVector &vec, - typename LIBC_NAMESPACE::cpp::type_identity::type default_val) { +static optional pop_front(FixedVector &vec) { if (vec.empty()) - return default_val; + return nullopt; // TODO: Add front() and erase() to FixedVector, then clean this up. T first = vec[0]; for (size_t i = 1; i < vec.size(); ++i) @@ -58,13 +57,6 @@ pop_front_or(FixedVector &vec, return first; } -// TODO: Add string::operator+=(string_view), then remove this helper. -static void append_bytes(string &str, const void *data, size_t len) { - size_t old_size = str.size(); - str.resize(old_size + len); - LIBC_NAMESPACE::inline_memcpy(str.data() + old_size, data, len); -} - namespace { struct FakeNetworkSyscallPolicyData { @@ -86,21 +78,21 @@ struct FakeNetworkSyscallPolicyData { template struct FakeNetworkSyscallPolicy { static ErrorOr socket(int domain, int type, int protocol) { DATA->socket_calls.push_back(tuple(domain, type, protocol)); - return pop_front_or(DATA->socket_results, Error(ENFILE)); + return pop_front(DATA->socket_results).value_or(Error(ENFILE)); } static ErrorOr sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *, socklen_t) { DATA->sendto_calls.push_back(tuple(fd, len, flags)); - append_bytes(DATA->sendto_data, buf, len); - return pop_front_or(DATA->sendto_results, static_cast(len)); + DATA->sendto_data += string_view(static_cast(buf), len); + return pop_front(DATA->sendto_results).value_or(static_cast(len)); } static ErrorOr recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *, socklen_t *) { DATA->recv_calls.push_back(tuple(fd, len, flags)); ErrorOr> chunk = - pop_front_or(DATA->recv_results, span()); + pop_front(DATA->recv_results).value_or(span()); if (!chunk.has_value()) return Error(chunk.error()); if (chunk->size() > len) @@ -111,7 +103,7 @@ template struct FakeNetworkSyscallPolicy { static ErrorOr close(int fd) { DATA->close_calls.push_back(fd); - return pop_front_or(DATA->close_results, 0); + return pop_front(DATA->close_results).value_or(0); } };