aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLexi Winter <lexi@hemlock.eden.le-fay.org>2025-03-26 12:01:39 +0000
committerLexi Winter <lexi@hemlock.eden.le-fay.org>2025-03-26 12:01:39 +0000
commit55b437198f77edb62d5ebd3457de5266cd67c0e2 (patch)
treef22621666e6d0e164fd8b4dd46202cff74a87d96
parent4902b36cbd2ec1f93d4f0520d5ec3897cce0f34c (diff)
downloadlibnvxx-55b437198f77edb62d5ebd3457de5266cd67c0e2.tar.gz
libnvxx-55b437198f77edb62d5ebd3457de5266cd67c0e2.tar.bz2
reorganise libnvxx source
-rw-r--r--libnvxx/Makefile12
-rw-r--r--libnvxx/const_nv_list.cc367
-rw-r--r--libnvxx/nv_list.cc807
-rw-r--r--libnvxx/nvxx.cc1113
-rw-r--r--libnvxx/nvxx.h9
-rw-r--r--libnvxx/nvxx_base.h8
-rw-r--r--libnvxx/nvxx_util.h52
7 files changed, 1245 insertions, 1123 deletions
diff --git a/libnvxx/Makefile b/libnvxx/Makefile
index ed412e1..843644c 100644
--- a/libnvxx/Makefile
+++ b/libnvxx/Makefile
@@ -25,8 +25,16 @@ LIB_CXX= nvxx
LIBDIR= ${PREFIX}/lib
INCLUDEDIR= ${PREFIX}/include
SHLIB_MAJOR= 1
-INCS= nvxx.h nvxx_base.h nvxx_serialize.h
-SRCS= nvxx.cc nvxx_iterator.cc nvxx_serialize.cc
+INCS= nvxx.h \
+ nvxx_base.h \
+ nvxx_util.h \
+ nvxx_iterator.h \
+ nvxx_serialize.h
+SRCS= nvxx.cc \
+ nv_list.cc \
+ const_nv_list.cc \
+ nvxx_iterator.cc \
+ nvxx_serialize.cc
CXXSTD= c++23
CXXFLAGS+= -W -Wall -Wextra -Werror
LDADD= -lnv
diff --git a/libnvxx/const_nv_list.cc b/libnvxx/const_nv_list.cc
new file mode 100644
index 0000000..7929804
--- /dev/null
+++ b/libnvxx/const_nv_list.cc
@@ -0,0 +1,367 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or distribute
+ * this software, either in source code form or as a compiled binary, for any
+ * purpose, commercial or non-commercial, and by any means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors of
+ * this software dedicate any and all copyright interest in the software to the
+ * public domain. We make this dedication for the benefit of the public at
+ * large and to the detriment of our heirs and successors. We intend this
+ * dedication to be an overt act of relinquishment in perpetuity of all present
+ * and future rights to this software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <cerrno>
+#include <cassert>
+
+#include "nvxx.h"
+
+namespace bsd {
+
+/*
+ * const_nv_list
+ */
+
+const_nv_list::const_nv_list() noexcept
+ : __nv_list_base(nullptr, __detail::__nvlist_owning::__non_owning)
+{
+}
+
+// const_cast is safe here since a non-owning nvlist is never modified.
+const_nv_list::const_nv_list(::nvlist_t const *nvl) noexcept
+ : __nv_list_base(const_cast<::nvlist_t *>(nvl),
+ __detail::__nvlist_owning::__non_owning)
+{
+}
+
+const_nv_list::const_nv_list(const_nv_list const &other) noexcept
+ : __nv_list_base(other.__m_nv,
+ __detail::__nvlist_owning::__non_owning)
+{
+}
+
+const_nv_list &
+const_nv_list::operator=(const_nv_list const &other) noexcept
+{
+ if (this != &other) {
+ /* This is not a leak since we never own the nvlist_t. */
+ __m_nv = other.__m_nv;
+ }
+
+ return *this;
+}
+
+const_nv_list &
+const_nv_list::operator=(nv_list const &other) noexcept
+{
+ /* This is not a leak since we never own the nvlist_t. */
+ __m_nv = other.__m_nv;
+ return *this;
+}
+
+::nvlist_t const *
+const_nv_list::ptr() const
+{
+ return __m_nv;
+}
+
+namespace __detail {
+
+std::error_code
+__const_nv_list::error() const noexcept
+{
+ if (auto const err = nvlist_error(__m_nv); err != 0)
+ return std::make_error_code(std::errc(err));
+ return {};
+}
+
+bool
+__const_nv_list::exists(std::string_view key) const
+{
+ return ::nvlist_exists(__m_nv, std::string(key).c_str());
+}
+
+bool
+__const_nv_list::empty() const noexcept
+{
+ return ::nvlist_empty(__m_nv);
+}
+
+int
+__const_nv_list::flags() const noexcept
+{
+ return ::nvlist_flags(__m_nv);
+}
+
+bool
+__const_nv_list::in_array() const noexcept
+{
+ return ::nvlist_in_array(__m_nv);
+}
+
+__const_nv_list::operator bool() const noexcept
+{
+ return ::nvlist_error(__m_nv) == 0;
+}
+
+void
+__const_nv_list::send(int fd) const
+{
+ if (::nvlist_send(fd, __m_nv) == 0)
+ return;
+
+ throw std::system_error(error());
+}
+
+void
+__const_nv_list::dump(int fd) const noexcept
+{
+ ::nvlist_dump(__m_nv, fd);
+}
+
+void
+__const_nv_list::fdump(std::FILE *__fp) const noexcept
+{
+ ::nvlist_fdump(__m_nv, __fp);
+}
+
+std::size_t
+__const_nv_list::packed_size() const noexcept
+{
+ return ::nvlist_size(__m_nv);
+}
+
+std::vector<std::byte>
+__const_nv_list::pack() const
+{
+ auto size = std::size_t{};
+
+ if (auto *data = nvlist_pack(__m_nv, &size); data != nullptr) {
+ auto bytes = ptr_guard(static_cast<std::byte *>(data));
+ return {bytes.ptr, bytes.ptr + size};
+ }
+
+ throw std::system_error(error());
+}
+
+/*
+ * null operations
+ */
+
+bool
+__const_nv_list::exists_null(std::string_view key) const
+{
+ return ::nvlist_exists_null(__m_nv, std::string(key).c_str());
+}
+
+/*
+ * bool operations
+ */
+
+bool
+__const_nv_list::exists_bool(std::string_view key) const
+{
+ return ::nvlist_exists_bool(__m_nv, std::string(key).c_str());
+}
+
+bool
+__const_nv_list::get_bool(std::string_view key) const
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_bool(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ return ::nvlist_get_bool(__m_nv, skey.c_str());
+}
+
+bool
+__const_nv_list::exists_bool_array(std::string_view key) const
+{
+ return ::nvlist_exists_bool_array(__m_nv, std::string(key).c_str());
+}
+
+std::span<bool const>
+__const_nv_list::get_bool_array(std::string_view key) const
+{
+ auto nitems = std::size_t{};
+ auto *data = ::nvlist_get_bool_array(__m_nv,
+ std::string(key).c_str(),
+ &nitems);
+ return {data, nitems};
+}
+
+/*
+ * number operations
+ */
+
+bool
+__const_nv_list::exists_number(std::string_view key) const
+{
+ return ::nvlist_exists_number(__m_nv, std::string(key).c_str());
+}
+
+std::uint64_t
+__const_nv_list::get_number(std::string_view key) const
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_number(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ return ::nvlist_get_number(__m_nv, skey.c_str());
+}
+
+bool
+__const_nv_list::exists_number_array(std::string_view key) const
+{
+ return ::nvlist_exists_number_array(__m_nv, std::string(key).c_str());
+}
+
+std::span<std::uint64_t const>
+__const_nv_list::get_number_array(std::string_view key) const
+{
+ auto nitems = std::size_t{};
+ auto *data = ::nvlist_get_number_array(
+ __m_nv, std::string(key).c_str(), &nitems);
+ return {data, nitems};
+}
+
+/*
+ * string operations
+ */
+
+bool
+__const_nv_list::exists_string(std::string_view key) const
+{
+ return ::nvlist_exists_string(__m_nv, std::string(key).c_str());
+}
+
+std::string_view
+__const_nv_list::get_string(std::string_view key) const
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_string(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ return nvlist_get_string(__m_nv, skey.c_str());
+}
+
+bool
+__const_nv_list::exists_string_array(std::string_view key) const
+{
+ return nvlist_exists_string_array(__m_nv, std::string(key).c_str());
+}
+
+std::vector<std::string_view>
+__const_nv_list::get_string_array(std::string_view key) const
+{
+ auto nitems = std::size_t{};
+ auto *data = nvlist_get_string_array(__m_nv, std::string(key).c_str(),
+ &nitems);
+ return std::span(data, data + nitems)
+ | construct<std::string_view>()
+ | std::ranges::to<std::vector>();
+}
+
+/*
+ * nv_list operations
+ */
+
+bool
+__const_nv_list::exists_nvlist(std::string_view key) const
+{
+ return nvlist_exists_nvlist(__m_nv, std::string(key).c_str());
+}
+
+const_nv_list
+__const_nv_list::get_nvlist(std::string_view key) const
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_nvlist(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ auto nvl = ::nvlist_get_nvlist(__m_nv, skey.c_str());
+ return const_nv_list(nvl);
+}
+
+bool
+__const_nv_list::exists_nvlist_array(std::string_view key) const
+{
+ return nvlist_exists_nvlist_array(__m_nv, std::string(key).c_str());
+}
+
+std::vector<const_nv_list>
+__const_nv_list::get_nvlist_array(std::string_view key) const
+{
+ auto nitems = std::size_t{};
+ auto *data = nvlist_get_nvlist_array(__m_nv, std::string(key).c_str(),
+ &nitems);
+ return {std::from_range,
+ std::span(data, nitems) | construct<const_nv_list>()};
+}
+
+/*
+ * descriptor operations
+ */
+
+int
+__const_nv_list::get_descriptor(std::string_view key) const
+{
+ return ::nvlist_get_descriptor(__m_nv, std::string(key).c_str());
+}
+
+std::span<int const>
+__const_nv_list::get_descriptor_array(std::string_view key) const
+{
+ auto nitems = std::size_t{};
+ auto *data = ::nvlist_get_descriptor_array(
+ __m_nv, std::string(key).c_str(), &nitems);
+ return {data, nitems};
+}
+
+bool
+__const_nv_list::exists_descriptor(std::string_view key) const
+{
+ return ::nvlist_exists_descriptor(__m_nv, std::string(key).c_str());
+}
+
+bool
+__const_nv_list::exists_descriptor_array(std::string_view key) const
+{
+ return ::nvlist_exists_descriptor_array(__m_nv,
+ std::string(key).c_str());
+}
+
+/*
+ * binary operations
+ */
+
+bool
+__const_nv_list::exists_binary(std::string_view key) const
+{
+ return ::nvlist_exists_binary(__m_nv, std::string(key).c_str());
+}
+
+std::span<std::byte const>
+__const_nv_list::get_binary(std::string_view key) const
+{
+ auto size = std::size_t{};
+ auto *data = nvlist_get_binary(__m_nv, std::string(key).c_str(),
+ &size);
+ return {static_cast<std::byte const *>(data), size};
+}
+
+} // namespace bsd::__detail
+} // namespace bsd
diff --git a/libnvxx/nv_list.cc b/libnvxx/nv_list.cc
new file mode 100644
index 0000000..12c2c39
--- /dev/null
+++ b/libnvxx/nv_list.cc
@@ -0,0 +1,807 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or distribute
+ * this software, either in source code form or as a compiled binary, for any
+ * purpose, commercial or non-commercial, and by any means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors of
+ * this software dedicate any and all copyright interest in the software to the
+ * public domain. We make this dedication for the benefit of the public at
+ * large and to the detriment of our heirs and successors. We intend this
+ * dedication to be an overt act of relinquishment in perpetuity of all present
+ * and future rights to this software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <cerrno>
+#include <cassert>
+
+#include "nvxx.h"
+
+namespace bsd {
+
+/*
+ * nv_list
+ */
+
+nv_list::nv_list(int flags)
+ : __nv_list_base(flags)
+{
+ if (__m_nv == nullptr)
+ throw std::system_error(
+ std::error_code(errno, std::system_category()));
+}
+
+nv_list::nv_list(::nvlist_t *nvl) noexcept
+ : __nv_list_base(nvl, __detail::__nvlist_owning::__owning)
+{
+}
+
+nv_list::nv_list(const_nv_list const &other)
+ : __nv_list_base(::nvlist_clone(other.ptr()),
+ __detail::__nvlist_owning::__owning)
+{
+ if (__m_nv == nullptr)
+ throw std::system_error(
+ std::error_code(errno, std::system_category()));
+}
+
+nv_list::nv_list(nv_list const &other)
+ : __nv_list_base(::nvlist_clone(other.__m_nv),
+ __detail::__nvlist_owning::__owning)
+{
+ if (__m_nv == nullptr)
+ throw std::system_error(
+ std::error_code(errno, std::system_category()));
+}
+
+nv_list::nv_list(nv_list &&other) noexcept
+ : __nv_list_base(std::exchange(other.__m_nv, nullptr),
+ __detail::__nvlist_owning::__owning)
+{
+}
+
+nv_list &
+nv_list::operator=(nv_list const &other)
+{
+ if (this != &other) {
+ auto *clone = nvlist_clone(other.__m_nv);
+ if (clone == nullptr)
+ throw std::system_error(
+ std::error_code(errno,
+ std::system_category()));
+ __free_nv();
+ __m_nv = clone;
+ __m_owning = __detail::__nvlist_owning::__owning;
+ }
+
+ return *this;
+}
+
+nv_list &
+nv_list::operator=(nv_list &&other) noexcept
+{
+ if (this != &other) {
+ __m_nv = std::exchange(other.__m_nv, nullptr);
+ __m_owning = __detail::__nvlist_owning::__owning;
+ }
+
+ return *this;
+}
+
+::nvlist_t *
+nv_list::ptr()
+{
+ return __m_nv;
+}
+
+::nvlist_t const *
+nv_list::ptr() const
+{
+ return __m_nv;
+}
+
+::nvlist_t *
+nv_list::release() &&
+{
+ return std::exchange(__m_nv, nullptr);
+}
+
+nv_list
+nv_list::unpack(std::span<std::byte> data, int flags)
+{
+ if (auto nv = ::nvlist_unpack(std::ranges::data(data),
+ std::ranges::size(data),
+ flags);
+ nv != nullptr) {
+ return nv_list(nv);
+ }
+
+ throw std::system_error(
+ std::error_code(errno, std::system_category()));
+}
+
+nv_list
+nv_list::recv(int fd, int flags)
+{
+ if (auto *nv = ::nvlist_recv(fd, flags); nv != nullptr)
+ return nv_list(nv);
+
+ throw std::system_error(
+ std::error_code(errno, std::system_category()));
+}
+
+nv_list
+nv_list::xfer(int fd, nv_list &&nvl, int flags)
+{
+ if (auto *nv = ::nvlist_xfer(fd, nvl.__m_nv, flags);
+ nv != nullptr) {
+ // nvlist_xfer destroys the original list
+ nvl.__m_nv = nullptr;
+ return nv_list(nv);
+ }
+
+ throw std::system_error(
+ std::error_code(errno, std::system_category()));
+}
+
+namespace __detail {
+
+/*
+ * __nv_list
+ */
+
+void
+__nv_list::set_error(int error) noexcept
+{
+ ::nvlist_set_error(__m_nv, error);
+}
+
+__nv_list::operator const_nv_list() const
+{
+ return const_nv_list(__m_nv);
+}
+
+void
+__nv_list::free(std::string_view key)
+{
+ ::nvlist_free(__m_nv, std::string(key).c_str());
+}
+
+/*
+ * null operations
+ */
+
+void
+__nv_list::add_null(std::string_view key)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_null(__m_nv, skey.c_str());
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::free_null(std::string_view key)
+{
+ ::nvlist_free_null(__m_nv, std::string(key).c_str());
+}
+
+/*
+ * bool operations
+ */
+
+void
+__nv_list::add_bool(std::string_view key, bool value)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_bool(__m_nv, skey.c_str(), value);
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+bool
+__nv_list::take_bool(std::string_view key)
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_bool(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ return ::nvlist_take_bool(__m_nv, skey.c_str());
+}
+
+void
+__nv_list::free_bool(std::string_view key)
+{
+ ::nvlist_free_bool(__m_nv, std::string(key).c_str());
+}
+
+std::vector<bool>
+__nv_list::take_bool_array(std::string_view key)
+{
+ auto nitems = std::size_t{};
+ auto ptr = ptr_guard(::nvlist_take_bool_array(__m_nv,
+ std::string(key).c_str(),
+ &nitems));
+ return std::vector<bool>(ptr.ptr, ptr.ptr + nitems);
+}
+
+void
+__nv_list::add_bool_array(std::string_view key,
+ std::span<bool const> value)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_bool_array(__m_nv, skey.c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_bool_array(std::string_view key, std::span<bool> value)
+{
+ ::nvlist_move_bool_array(__m_nv, std::string(key).c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+}
+
+void
+__nv_list::append_bool_array(std::string_view key, bool value)
+{
+ ::nvlist_append_bool_array(__m_nv, std::string(key).c_str(), value);
+}
+
+void
+__nv_list::free_bool_array(std::string_view key)
+{
+ ::nvlist_free_bool_array(__m_nv, std::string(key).c_str());
+}
+
+/*
+ * number operations
+ */
+
+void
+__nv_list::add_number(std::string_view key, std::uint64_t value)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_number(__m_nv, skey.c_str(), value);
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+std::uint64_t
+__nv_list::take_number(std::string_view key)
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_number(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ return ::nvlist_take_number(__m_nv, skey.c_str());
+}
+
+void
+__nv_list::free_number(std::string_view key)
+{
+ ::nvlist_free_number(__m_nv, std::string(key).c_str());
+}
+
+std::vector<std::uint64_t>
+__nv_list::take_number_array(std::string_view key)
+{
+ auto nitems = std::size_t{};
+ auto ptr = ptr_guard(
+ ::nvlist_take_number_array(__m_nv,
+ std::string(key).c_str(),
+ &nitems));
+ return {ptr.ptr, ptr.ptr + nitems};
+}
+
+void
+__nv_list::add_number_array(std::string_view key,
+ std::span<std::uint64_t const> value)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_number_array(__m_nv, skey.c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_number_array(std::string_view key,
+ std::span<std::uint64_t> value)
+{
+ ::nvlist_move_number_array(__m_nv, std::string(key).c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+}
+
+void
+__nv_list::append_number_array(std::string_view key, std::uint64_t value)
+{
+ ::nvlist_append_number_array(__m_nv, std::string(key).c_str(), value);
+}
+
+void
+__nv_list::free_number_array(std::string_view key)
+{
+ ::nvlist_free_number_array(__m_nv, std::string(key).c_str());
+}
+
+/*
+ * string operations
+ */
+
+void
+__nv_list::add_string(std::string_view key, std::string_view value)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_string(__m_nv, skey.c_str(), std::string(value).c_str());
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_string(std::string_view key, char *value)
+{
+ ::nvlist_move_string(__m_nv, std::string(key).c_str(), value);
+}
+
+std::string
+__nv_list::take_string(std::string_view key)
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_string(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ return nvlist_take_string(__m_nv, skey.c_str());
+}
+
+void
+__nv_list::free_string(std::string_view key)
+{
+ nvlist_free_string(__m_nv, std::string(key).c_str());
+}
+
+void
+__nv_list::add_string_array(std::string_view key,
+ std::span<std::string_view const> value)
+{
+ auto skey = std::string(key);
+
+ // nvlist_add_string_array expects an array of NUL-terminated
+ // C strings.
+
+ auto strings = value
+ | construct<std::string>()
+ | std::ranges::to<std::vector>();
+
+ auto ptrs = strings
+ | std::views::transform(&std::string::c_str)
+ | std::ranges::to<std::vector>();
+
+ ::nvlist_add_string_array(__m_nv, skey.c_str(),
+ ptrs.data(), ptrs.size());
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_string_array(std::string_view key,
+ std::span<char *> value)
+{
+ ::nvlist_move_string_array(__m_nv, std::string(key).c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+}
+
+void
+__nv_list::append_string_array(std::string_view key, std::string_view value)
+{
+ ::nvlist_append_string_array(__m_nv,
+ std::string(key).c_str(),
+ std::string(value).c_str());
+}
+
+std::vector<std::string>
+__nv_list::take_string_array(std::string_view key)
+{
+ auto nitems = std::size_t{};
+ auto *data = nvlist_take_string_array(__m_nv, std::string(key).c_str(),
+ &nitems);
+ return std::span(data, data + nitems)
+ | construct<std::string>()
+ | std::ranges::to<std::vector>();
+}
+
+void
+__nv_list::free_string_array(std::string_view key)
+{
+ ::nvlist_free_string_array(__m_nv, std::string(key).c_str());
+}
+
+/*
+ * nv_list operations
+ */
+
+void
+__nv_list::add_nvlist(std::string_view key, const_nv_list const &other)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_nvlist(__m_nv, skey.c_str(), other.__m_nv);
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_nvlist(std::string_view key, nv_list &&value)
+{
+ ::nvlist_move_nvlist(__m_nv, std::string(key).c_str(),
+ std::exchange(value.__m_nv, nullptr));
+}
+
+void
+__nv_list::move_nvlist(std::string_view key, ::nvlist_t *value)
+{
+ ::nvlist_move_nvlist(__m_nv, std::string(key).c_str(), value);
+}
+
+nv_list
+__nv_list::take_nvlist(std::string_view key)
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_nvlist(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ auto nvl = nvlist_take_nvlist(__m_nv, skey.c_str());
+ return nv_list(nvl);
+}
+
+void
+__nv_list::free_nvlist(std::string_view key)
+{
+ nvlist_free_nvlist(__m_nv, std::string(key).c_str());
+}
+
+void
+__nv_list::add_nvlist_array(std::string_view key,
+ std::span<const_nv_list const> value)
+{
+ auto skey = std::string(key);
+
+ auto ptrs = value
+ | std::views::transform(&const_nv_list::__m_nv)
+ | std::ranges::to<std::vector>();
+
+ ::nvlist_add_nvlist_array(__m_nv, skey.c_str(),
+ ptrs.data(), ptrs.size());
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::add_nvlist_array(std::string_view key,
+ std::span<nv_list const> value)
+{
+ auto skey = std::string(key);
+
+ auto ptrs = value
+ | std::views::transform(&nv_list::__m_nv)
+ | std::ranges::to<std::vector>();
+
+ nvlist_add_nvlist_array(__m_nv, skey.c_str(),
+ ptrs.data(), ptrs.size());
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_nvlist_array(std::string_view key,
+ std::span<::nvlist_t *> value)
+{
+ ::nvlist_move_nvlist_array(__m_nv, std::string(key).c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+}
+
+void
+__nv_list::append_nvlist_array(std::string_view key,
+ const_nv_list const &value)
+{
+ ::nvlist_append_nvlist_array(__m_nv, std::string(key).c_str(),
+ value.__m_nv);
+}
+
+std::vector<nv_list>
+__nv_list::take_nvlist_array(std::string_view key)
+{
+ auto nitems = std::size_t{};
+ auto ptr = ptr_guard(
+ ::nvlist_take_nvlist_array(__m_nv,
+ std::string(key).c_str(),
+ &nitems));
+ return {std::from_range,
+ std::span(ptr.ptr, nitems) | construct<nv_list>()};
+}
+
+void
+__nv_list::free_nvlist_array(std::string_view key)
+{
+ ::nvlist_free_nvlist_array(__m_nv, std::string(key).c_str());
+}
+
+/*
+ * descriptor operations
+ */
+
+int
+__nv_list::take_descriptor(std::string_view key)
+{
+ return ::nvlist_take_descriptor(__m_nv, std::string(key).c_str());
+}
+
+void
+__nv_list::add_descriptor(std::string_view key, int value)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_descriptor(__m_nv, skey.c_str(), value);
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_descriptor(std::string_view key, int value)
+{
+ ::nvlist_move_descriptor(__m_nv, std::string(key).c_str(), value);
+}
+
+void
+__nv_list::free_descriptor(std::string_view key)
+{
+ ::nvlist_free_descriptor(__m_nv, std::string(key).c_str());
+}
+
+void
+__nv_list::append_descriptor_array(std::string_view key, int value)
+{
+ ::nvlist_append_descriptor_array(__m_nv,
+ std::string(key).c_str(),
+ value);
+}
+
+void
+__nv_list::add_descriptor_array(std::string_view key,
+ std::span<int const> value)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_descriptor_array(__m_nv, skey.c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_descriptor_array(std::string_view key, std::span<int> value)
+{
+ ::nvlist_add_descriptor_array(__m_nv, std::string(key).c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+}
+
+void
+__nv_list::free_descriptor_array(std::string_view key)
+{
+ ::nvlist_free_descriptor_array(__m_nv, std::string(key).c_str());
+}
+
+std::vector<int>
+__nv_list::take_descriptor_array(std::string_view key)
+{
+ auto nitems = std::size_t{};
+ auto ptr = ptr_guard(
+ ::nvlist_take_descriptor_array(__m_nv,
+ std::string(key).c_str(),
+ &nitems));
+ return {ptr.ptr, ptr.ptr + nitems};
+}
+
+/*
+ * binary operations
+ */
+
+void
+__nv_list::add_binary(std::string_view key, std::span<std::byte const> value)
+{
+ auto skey = std::string(key);
+
+ ::nvlist_add_binary(__m_nv, skey.c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+
+ switch (auto err = ::nvlist_error(__m_nv)) {
+ case 0:
+ return;
+
+ case EEXIST:
+ throw nv_key_exists(skey);
+
+ default:
+ throw std::system_error(
+ std::error_code(err, std::generic_category()));
+ }
+}
+
+void
+__nv_list::move_binary(std::string_view key, std::span<std::byte> value)
+{
+ ::nvlist_move_binary(__m_nv, std::string(key).c_str(),
+ std::ranges::data(value),
+ std::ranges::size(value));
+}
+
+void
+__nv_list::free_binary(std::string_view key)
+{
+ ::nvlist_free_binary(__m_nv, std::string(key).c_str());
+}
+
+std::vector<std::byte>
+__nv_list::take_binary(std::string_view key)
+{
+ auto skey = std::string(key);
+
+ if (!::nvlist_exists_binary(__m_nv, skey.c_str()))
+ throw nv_key_not_found(skey);
+
+ auto size = std::size_t{};
+ auto *data = ::nvlist_take_binary(__m_nv, skey.c_str(), &size);
+ auto ptr = ptr_guard(static_cast<std::byte *>(data));
+ return {ptr.ptr, ptr.ptr + size};
+}
+
+} // namespace bsd
+} // namespace detail
diff --git a/libnvxx/nvxx.cc b/libnvxx/nvxx.cc
index 8decebf..d730f01 100644
--- a/libnvxx/nvxx.cc
+++ b/libnvxx/nvxx.cc
@@ -25,206 +25,6 @@
#include "nvxx.h"
-namespace {
-
-/*
- * Some useful helper types.
- */
-
-template<typename T>
-struct ptr_guard {
- ptr_guard(T *ptr_) : ptr(ptr_) {}
-
- ~ptr_guard() {
- std::free(ptr);
- }
-
- T *ptr;
-};
-
-template<typename T>
-auto construct = std::views::transform([] (auto &&value) {
- return T(std::forward<decltype(value)>(value));
-});
-
-}
-
-namespace bsd {
-
-/*
- * const_nv_list
- */
-
-const_nv_list::const_nv_list() noexcept
- : __nv_list_base(nullptr, __detail::__nvlist_owning::__non_owning)
-{
-}
-
-// const_cast is safe here since a non-owning nvlist is never modified.
-const_nv_list::const_nv_list(::nvlist_t const *nvl) noexcept
- : __nv_list_base(const_cast<::nvlist_t *>(nvl),
- __detail::__nvlist_owning::__non_owning)
-{
-}
-
-const_nv_list::const_nv_list(const_nv_list const &other) noexcept
- : __nv_list_base(other.__m_nv,
- __detail::__nvlist_owning::__non_owning)
-{
-}
-
-const_nv_list &
-const_nv_list::operator=(const_nv_list const &other) noexcept
-{
- if (this != &other) {
- /* This is not a leak since we never own the nvlist_t. */
- __m_nv = other.__m_nv;
- }
-
- return *this;
-}
-
-const_nv_list &
-const_nv_list::operator=(nv_list const &other) noexcept
-{
- /* This is not a leak since we never own the nvlist_t. */
- __m_nv = other.__m_nv;
- return *this;
-}
-
-::nvlist_t const *
-const_nv_list::ptr() const
-{
- return __m_nv;
-}
-
-/*
- * nv_list
- */
-
-nv_list::nv_list(int flags)
- : __nv_list_base(flags)
-{
- if (__m_nv == nullptr)
- throw std::system_error(
- std::error_code(errno, std::system_category()));
-}
-
-nv_list::nv_list(::nvlist_t *nvl) noexcept
- : __nv_list_base(nvl, __detail::__nvlist_owning::__owning)
-{
-}
-
-nv_list::nv_list(const_nv_list const &other)
- : __nv_list_base(::nvlist_clone(other.ptr()),
- __detail::__nvlist_owning::__owning)
-{
- if (__m_nv == nullptr)
- throw std::system_error(
- std::error_code(errno, std::system_category()));
-}
-
-nv_list::nv_list(nv_list const &other)
- : __nv_list_base(::nvlist_clone(other.__m_nv),
- __detail::__nvlist_owning::__owning)
-{
- if (__m_nv == nullptr)
- throw std::system_error(
- std::error_code(errno, std::system_category()));
-}
-
-nv_list::nv_list(nv_list &&other) noexcept
- : __nv_list_base(std::exchange(other.__m_nv, nullptr),
- __detail::__nvlist_owning::__owning)
-{
-}
-
-nv_list &
-nv_list::operator=(nv_list const &other)
-{
- if (this != &other) {
- auto *clone = nvlist_clone(other.__m_nv);
- if (clone == nullptr)
- throw std::system_error(
- std::error_code(errno,
- std::system_category()));
- __free_nv();
- __m_nv = clone;
- __m_owning = __detail::__nvlist_owning::__owning;
- }
-
- return *this;
-}
-
-nv_list &
-nv_list::operator=(nv_list &&other) noexcept
-{
- if (this != &other) {
- __m_nv = std::exchange(other.__m_nv, nullptr);
- __m_owning = __detail::__nvlist_owning::__owning;
- }
-
- return *this;
-}
-
-::nvlist_t *
-nv_list::ptr()
-{
- return __m_nv;
-}
-
-::nvlist_t const *
-nv_list::ptr() const
-{
- return __m_nv;
-}
-
-::nvlist_t *
-nv_list::release() &&
-{
- return std::exchange(__m_nv, nullptr);
-}
-
-nv_list
-nv_list::unpack(std::span<std::byte> data, int flags)
-{
- if (auto nv = ::nvlist_unpack(std::ranges::data(data),
- std::ranges::size(data),
- flags);
- nv != nullptr) {
- return nv_list(nv);
- }
-
- throw std::system_error(
- std::error_code(errno, std::system_category()));
-}
-
-nv_list
-nv_list::recv(int fd, int flags)
-{
- if (auto *nv = ::nvlist_recv(fd, flags); nv != nullptr)
- return nv_list(nv);
-
- throw std::system_error(
- std::error_code(errno, std::system_category()));
-}
-
-nv_list
-nv_list::xfer(int fd, nv_list &&nvl, int flags)
-{
- if (auto *nv = ::nvlist_xfer(fd, nvl.__m_nv, flags);
- nv != nullptr) {
- // nvlist_xfer destroys the original list
- nvl.__m_nv = nullptr;
- return nv_list(nv);
- }
-
- throw std::system_error(
- std::error_code(errno, std::system_category()));
-}
-
-} // namespace bsd
-
namespace bsd::__detail {
/*
@@ -260,917 +60,4 @@ __nv_list_base::__free_nv() noexcept
::nvlist_destroy(__m_nv);
}
-/*
- * __const_nv_list
- */
-
-std::error_code
-__const_nv_list::error() const noexcept
-{
- if (auto const err = nvlist_error(__m_nv); err != 0)
- return std::make_error_code(std::errc(err));
- return {};
-}
-
-bool
-__const_nv_list::exists(std::string_view key) const
-{
- return ::nvlist_exists(__m_nv, std::string(key).c_str());
-}
-
-bool
-__const_nv_list::empty() const noexcept
-{
- return ::nvlist_empty(__m_nv);
-}
-
-int
-__const_nv_list::flags() const noexcept
-{
- return ::nvlist_flags(__m_nv);
-}
-
-bool
-__const_nv_list::in_array() const noexcept
-{
- return ::nvlist_in_array(__m_nv);
-}
-
-__const_nv_list::operator bool() const noexcept
-{
- return ::nvlist_error(__m_nv) == 0;
-}
-
-void
-__const_nv_list::send(int fd) const
-{
- if (::nvlist_send(fd, __m_nv) == 0)
- return;
-
- throw std::system_error(error());
-}
-
-void
-__const_nv_list::dump(int fd) const noexcept
-{
- ::nvlist_dump(__m_nv, fd);
-}
-
-void
-__const_nv_list::fdump(std::FILE *__fp) const noexcept
-{
- ::nvlist_fdump(__m_nv, __fp);
-}
-
-std::size_t
-__const_nv_list::packed_size() const noexcept
-{
- return ::nvlist_size(__m_nv);
-}
-
-std::vector<std::byte>
-__const_nv_list::pack() const
-{
- auto size = std::size_t{};
-
- if (auto *data = nvlist_pack(__m_nv, &size); data != nullptr) {
- auto bytes = ptr_guard(static_cast<std::byte *>(data));
- return {bytes.ptr, bytes.ptr + size};
- }
-
- throw std::system_error(error());
-}
-
-/*
- * __nv_list
- */
-
-
-void
-__nv_list::set_error(int error) noexcept
-{
- ::nvlist_set_error(__m_nv, error);
-}
-
-__nv_list::operator const_nv_list() const
-{
- return const_nv_list(__m_nv);
-}
-
-void
-__nv_list::free(std::string_view key)
-{
- ::nvlist_free(__m_nv, std::string(key).c_str());
-}
-
-/*
- * null operations
- */
-
-bool
-__const_nv_list::exists_null(std::string_view key) const
-{
- return ::nvlist_exists_null(__m_nv, std::string(key).c_str());
-}
-
-void
-__nv_list::add_null(std::string_view key)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_null(__m_nv, skey.c_str());
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::free_null(std::string_view key)
-{
- ::nvlist_free_null(__m_nv, std::string(key).c_str());
-}
-
-/*
- * bool operations
- */
-
-void
-__nv_list::add_bool(std::string_view key, bool value)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_bool(__m_nv, skey.c_str(), value);
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-bool
-__const_nv_list::exists_bool(std::string_view key) const
-{
- return ::nvlist_exists_bool(__m_nv, std::string(key).c_str());
-}
-
-bool
-__const_nv_list::get_bool(std::string_view key) const
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_bool(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- return ::nvlist_get_bool(__m_nv, skey.c_str());
-}
-
-bool
-__nv_list::take_bool(std::string_view key)
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_bool(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- return ::nvlist_take_bool(__m_nv, skey.c_str());
-}
-
-void
-__nv_list::free_bool(std::string_view key)
-{
- ::nvlist_free_bool(__m_nv, std::string(key).c_str());
-}
-
-bool
-__const_nv_list::exists_bool_array(std::string_view key) const
-{
- return ::nvlist_exists_bool_array(__m_nv, std::string(key).c_str());
-}
-
-std::span<bool const>
-__const_nv_list::get_bool_array(std::string_view key) const
-{
- auto nitems = std::size_t{};
- auto *data = ::nvlist_get_bool_array(__m_nv,
- std::string(key).c_str(),
- &nitems);
- return {data, nitems};
-}
-
-std::vector<bool>
-__nv_list::take_bool_array(std::string_view key)
-{
- auto nitems = std::size_t{};
- auto ptr = ptr_guard(::nvlist_take_bool_array(__m_nv,
- std::string(key).c_str(),
- &nitems));
- return std::vector<bool>(ptr.ptr, ptr.ptr + nitems);
-}
-
-void
-__nv_list::add_bool_array(std::string_view key,
- std::span<bool const> value)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_bool_array(__m_nv, skey.c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_bool_array(std::string_view key, std::span<bool> value)
-{
- ::nvlist_move_bool_array(__m_nv, std::string(key).c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-}
-
-void
-__nv_list::append_bool_array(std::string_view key, bool value)
-{
- ::nvlist_append_bool_array(__m_nv, std::string(key).c_str(), value);
-}
-
-void
-__nv_list::free_bool_array(std::string_view key)
-{
- ::nvlist_free_bool_array(__m_nv, std::string(key).c_str());
-}
-
-/*
- * number operations
- */
-
-void
-__nv_list::add_number(std::string_view key, std::uint64_t value)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_number(__m_nv, skey.c_str(), value);
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-bool
-__const_nv_list::exists_number(std::string_view key) const
-{
- return ::nvlist_exists_number(__m_nv, std::string(key).c_str());
-}
-
-std::uint64_t
-__const_nv_list::get_number(std::string_view key) const
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_number(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- return ::nvlist_get_number(__m_nv, skey.c_str());
-}
-
-std::uint64_t
-__nv_list::take_number(std::string_view key)
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_number(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- return ::nvlist_take_number(__m_nv, skey.c_str());
-}
-
-void
-__nv_list::free_number(std::string_view key)
-{
- ::nvlist_free_number(__m_nv, std::string(key).c_str());
-}
-
-bool
-__const_nv_list::exists_number_array(std::string_view key) const
-{
- return ::nvlist_exists_number_array(__m_nv, std::string(key).c_str());
-}
-
-std::span<std::uint64_t const>
-__const_nv_list::get_number_array(std::string_view key) const
-{
- auto nitems = std::size_t{};
- auto *data = ::nvlist_get_number_array(
- __m_nv, std::string(key).c_str(), &nitems);
- return {data, nitems};
-}
-
-std::vector<std::uint64_t>
-__nv_list::take_number_array(std::string_view key)
-{
- auto nitems = std::size_t{};
- auto ptr = ptr_guard(
- ::nvlist_take_number_array(__m_nv,
- std::string(key).c_str(),
- &nitems));
- return {ptr.ptr, ptr.ptr + nitems};
-}
-
-void
-__nv_list::add_number_array(std::string_view key,
- std::span<std::uint64_t const> value)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_number_array(__m_nv, skey.c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_number_array(std::string_view key,
- std::span<std::uint64_t> value)
-{
- ::nvlist_move_number_array(__m_nv, std::string(key).c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-}
-
-void
-__nv_list::append_number_array(std::string_view key, std::uint64_t value)
-{
- ::nvlist_append_number_array(__m_nv, std::string(key).c_str(), value);
-}
-
-void
-__nv_list::free_number_array(std::string_view key)
-{
- ::nvlist_free_number_array(__m_nv, std::string(key).c_str());
-}
-
-/*
- * string operations
- */
-
-void
-__nv_list::add_string(std::string_view key, std::string_view value)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_string(__m_nv, skey.c_str(), std::string(value).c_str());
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_string(std::string_view key, char *value)
-{
- ::nvlist_move_string(__m_nv, std::string(key).c_str(), value);
-}
-
-bool
-__const_nv_list::exists_string(std::string_view key) const
-{
- return nvlist_exists_string(__m_nv, std::string(key).c_str());
-}
-
-std::string_view
-__const_nv_list::get_string(std::string_view key) const
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_string(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- return nvlist_get_string(__m_nv, skey.c_str());
-}
-
-std::string
-__nv_list::take_string(std::string_view key)
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_string(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- return nvlist_take_string(__m_nv, skey.c_str());
-}
-
-void
-__nv_list::free_string(std::string_view key)
-{
- nvlist_free_string(__m_nv, std::string(key).c_str());
-}
-
-void
-__nv_list::add_string_array(std::string_view key,
- std::span<std::string_view const> value)
-{
- auto skey = std::string(key);
-
- // nvlist_add_string_array expects an array of NUL-terminated
- // C strings.
-
- auto strings = value
- | construct<std::string>()
- | std::ranges::to<std::vector>();
-
- auto ptrs = strings
- | std::views::transform(&std::string::c_str)
- | std::ranges::to<std::vector>();
-
- ::nvlist_add_string_array(__m_nv, skey.c_str(),
- ptrs.data(), ptrs.size());
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_string_array(std::string_view key,
- std::span<char *> value)
-{
- ::nvlist_move_string_array(__m_nv, std::string(key).c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-}
-
-void
-__nv_list::append_string_array(std::string_view key, std::string_view value)
-{
- ::nvlist_append_string_array(__m_nv,
- std::string(key).c_str(),
- std::string(value).c_str());
-}
-
-bool
-__const_nv_list::exists_string_array(std::string_view key) const
-{
- return nvlist_exists_string_array(__m_nv, std::string(key).c_str());
-}
-
-std::vector<std::string_view>
-__const_nv_list::get_string_array(std::string_view key) const
-{
- auto nitems = std::size_t{};
- auto *data = nvlist_get_string_array(__m_nv, std::string(key).c_str(),
- &nitems);
- return std::span(data, data + nitems)
- | construct<std::string_view>()
- | std::ranges::to<std::vector>();
-}
-
-std::vector<std::string>
-__nv_list::take_string_array(std::string_view key)
-{
- auto nitems = std::size_t{};
- auto *data = nvlist_take_string_array(__m_nv, std::string(key).c_str(),
- &nitems);
- return std::span(data, data + nitems)
- | construct<std::string>()
- | std::ranges::to<std::vector>();
-}
-
-void
-__nv_list::free_string_array(std::string_view key)
-{
- ::nvlist_free_string_array(__m_nv, std::string(key).c_str());
-}
-
-/*
- * nv_list operations
- */
-
-void
-__nv_list::add_nvlist(std::string_view key, const_nv_list const &other)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_nvlist(__m_nv, skey.c_str(), other.__m_nv);
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_nvlist(std::string_view key, nv_list &&value)
-{
- ::nvlist_move_nvlist(__m_nv, std::string(key).c_str(),
- std::exchange(value.__m_nv, nullptr));
-}
-
-void
-__nv_list::move_nvlist(std::string_view key, ::nvlist_t *value)
-{
- ::nvlist_move_nvlist(__m_nv, std::string(key).c_str(), value);
-}
-
-bool
-__const_nv_list::exists_nvlist(std::string_view key) const
-{
- return nvlist_exists_nvlist(__m_nv, std::string(key).c_str());
-}
-
-const_nv_list
-__const_nv_list::get_nvlist(std::string_view key) const
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_nvlist(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- auto nvl = ::nvlist_get_nvlist(__m_nv, skey.c_str());
- return const_nv_list(nvl);
-}
-
-nv_list
-__nv_list::take_nvlist(std::string_view key)
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_nvlist(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- auto nvl = nvlist_take_nvlist(__m_nv, skey.c_str());
- return nv_list(nvl);
-}
-
-void
-__nv_list::free_nvlist(std::string_view key)
-{
- nvlist_free_nvlist(__m_nv, std::string(key).c_str());
-}
-
-bool
-__const_nv_list::exists_nvlist_array(std::string_view key) const
-{
- return nvlist_exists_nvlist_array(__m_nv, std::string(key).c_str());
-}
-
-void
-__nv_list::add_nvlist_array(std::string_view key,
- std::span<const_nv_list const> value)
-{
- auto skey = std::string(key);
-
- auto ptrs = value
- | std::views::transform(&const_nv_list::__m_nv)
- | std::ranges::to<std::vector>();
-
- ::nvlist_add_nvlist_array(__m_nv, skey.c_str(),
- ptrs.data(), ptrs.size());
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::add_nvlist_array(std::string_view key,
- std::span<nv_list const> value)
-{
- auto skey = std::string(key);
-
- auto ptrs = value
- | std::views::transform(&nv_list::__m_nv)
- | std::ranges::to<std::vector>();
-
- nvlist_add_nvlist_array(__m_nv, skey.c_str(),
- ptrs.data(), ptrs.size());
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_nvlist_array(std::string_view key,
- std::span<::nvlist_t *> value)
-{
- ::nvlist_move_nvlist_array(__m_nv, std::string(key).c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-}
-
-void
-__nv_list::append_nvlist_array(std::string_view key,
- const_nv_list const &value)
-{
- ::nvlist_append_nvlist_array(__m_nv, std::string(key).c_str(),
- value.__m_nv);
-}
-
-std::vector<const_nv_list>
-__const_nv_list::get_nvlist_array(std::string_view key) const
-{
- auto nitems = std::size_t{};
- auto *data = nvlist_get_nvlist_array(__m_nv, std::string(key).c_str(),
- &nitems);
- return {std::from_range,
- std::span(data, nitems) | construct<const_nv_list>()};
-}
-
-std::vector<nv_list>
-__nv_list::take_nvlist_array(std::string_view key)
-{
- auto nitems = std::size_t{};
- auto ptr = ptr_guard(
- ::nvlist_take_nvlist_array(__m_nv,
- std::string(key).c_str(),
- &nitems));
- return {std::from_range,
- std::span(ptr.ptr, nitems) | construct<nv_list>()};
-}
-
-void
-__nv_list::free_nvlist_array(std::string_view key)
-{
- ::nvlist_free_nvlist_array(__m_nv, std::string(key).c_str());
-}
-
-/*
- * descriptor operations
- */
-
-int
-__const_nv_list::get_descriptor(std::string_view key) const
-{
- return ::nvlist_get_descriptor(__m_nv, std::string(key).c_str());
-}
-
-int
-__nv_list::take_descriptor(std::string_view key)
-{
- return ::nvlist_take_descriptor(__m_nv, std::string(key).c_str());
-}
-
-void
-__nv_list::add_descriptor(std::string_view key, int value)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_descriptor(__m_nv, skey.c_str(), value);
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_descriptor(std::string_view key, int value)
-{
- ::nvlist_move_descriptor(__m_nv, std::string(key).c_str(), value);
-}
-
-void
-__nv_list::free_descriptor(std::string_view key)
-{
- ::nvlist_free_descriptor(__m_nv, std::string(key).c_str());
-}
-
-void
-__nv_list::append_descriptor_array(std::string_view key, int value)
-{
- ::nvlist_append_descriptor_array(__m_nv,
- std::string(key).c_str(),
- value);
-}
-
-void
-__nv_list::add_descriptor_array(std::string_view key,
- std::span<int const> value)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_descriptor_array(__m_nv, skey.c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_descriptor_array(std::string_view key, std::span<int> value)
-{
- ::nvlist_add_descriptor_array(__m_nv, std::string(key).c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-}
-
-std::span<int const>
-__const_nv_list::get_descriptor_array(std::string_view key) const
-{
- auto nitems = std::size_t{};
- auto *data = ::nvlist_get_descriptor_array(
- __m_nv, std::string(key).c_str(), &nitems);
- return {data, nitems};
-}
-
-void
-__nv_list::free_descriptor_array(std::string_view key)
-{
- ::nvlist_free_descriptor_array(__m_nv, std::string(key).c_str());
-}
-
-bool
-__const_nv_list::exists_descriptor(std::string_view key) const
-{
- return ::nvlist_exists_descriptor(__m_nv, std::string(key).c_str());
-}
-
-bool
-__const_nv_list::exists_descriptor_array(std::string_view key) const
-{
- return ::nvlist_exists_descriptor_array(__m_nv,
- std::string(key).c_str());
-}
-
-std::vector<int>
-__nv_list::take_descriptor_array(std::string_view key)
-{
- auto nitems = std::size_t{};
- auto ptr = ptr_guard(
- ::nvlist_take_descriptor_array(__m_nv,
- std::string(key).c_str(),
- &nitems));
- return {ptr.ptr, ptr.ptr + nitems};
-}
-
-/*
- * binary operations
- */
-
-bool
-__const_nv_list::exists_binary(std::string_view key) const
-{
- return ::nvlist_exists_binary(__m_nv, std::string(key).c_str());
-}
-
-void
-__nv_list::add_binary(std::string_view key, std::span<std::byte const> value)
-{
- auto skey = std::string(key);
-
- ::nvlist_add_binary(__m_nv, skey.c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-
- switch (auto err = ::nvlist_error(__m_nv)) {
- case 0:
- return;
-
- case EEXIST:
- throw nv_key_exists(skey);
-
- default:
- throw std::system_error(
- std::error_code(err, std::generic_category()));
- }
-}
-
-void
-__nv_list::move_binary(std::string_view key, std::span<std::byte> value)
-{
- ::nvlist_move_binary(__m_nv, std::string(key).c_str(),
- std::ranges::data(value),
- std::ranges::size(value));
-}
-
-void
-__nv_list::free_binary(std::string_view key)
-{
- ::nvlist_free_binary(__m_nv, std::string(key).c_str());
-}
-
-std::span<std::byte const>
-__const_nv_list::get_binary(std::string_view key) const
-{
- auto size = std::size_t{};
- auto *data = nvlist_get_binary(__m_nv, std::string(key).c_str(),
- &size);
- return {static_cast<std::byte const *>(data), size};
-}
-
-std::vector<std::byte>
-__nv_list::take_binary(std::string_view key)
-{
- auto skey = std::string(key);
-
- if (!::nvlist_exists_binary(__m_nv, skey.c_str()))
- throw nv_key_not_found(skey);
-
- auto size = std::size_t{};
- auto *data = ::nvlist_take_binary(__m_nv, skey.c_str(), &size);
- auto ptr = ptr_guard(static_cast<std::byte *>(data));
- return {ptr.ptr, ptr.ptr + size};
-}
-
} // namespace bsd::__detail
diff --git a/libnvxx/nvxx.h b/libnvxx/nvxx.h
index 53c95cc..2afab52 100644
--- a/libnvxx/nvxx.h
+++ b/libnvxx/nvxx.h
@@ -30,6 +30,15 @@
#include <sys/nv.h>
#include <sys/cnv.h>
+#include <expected>
+#include <ranges>
+#include <span>
+#include <system_error>
+#include <vector>
+#include <stdexcept>
+#include <format>
+
+#include "nvxx_util.h"
#include "nvxx_base.h"
#include "nvxx_iterator.h"
#include "nvxx_serialize.h"
diff --git a/libnvxx/nvxx_base.h b/libnvxx/nvxx_base.h
index 4700e79..77e5d53 100644
--- a/libnvxx/nvxx_base.h
+++ b/libnvxx/nvxx_base.h
@@ -27,14 +27,6 @@
# error include <nvxx.h> instead of including this header directly
#endif
-#include <expected>
-#include <ranges>
-#include <span>
-#include <system_error>
-#include <vector>
-#include <stdexcept>
-#include <format>
-
namespace bsd {
struct nv_list;
diff --git a/libnvxx/nvxx_util.h b/libnvxx/nvxx_util.h
new file mode 100644
index 0000000..2295541
--- /dev/null
+++ b/libnvxx/nvxx_util.h
@@ -0,0 +1,52 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or distribute
+ * this software, either in source code form or as a compiled binary, for any
+ * purpose, commercial or non-commercial, and by any means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors of
+ * this software dedicate any and all copyright interest in the software to the
+ * public domain. We make this dedication for the benefit of the public at
+ * large and to the detriment of our heirs and successors. We intend this
+ * dedication to be an overt act of relinquishment in perpetuity of all present
+ * and future rights to this software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NVXX_UTIL_H_INCLUDED
+#define _NVXX_UTIL_H_INCLUDED
+
+#ifndef _NVXX_H_INCLUDED
+# error include <nvxx.h> instead of including this header directly
+#endif
+
+// Some useful helper types.
+
+namespace bsd::__detail {
+
+template<typename T>
+struct ptr_guard {
+ ptr_guard(T *ptr_) : ptr(ptr_) {}
+
+ ~ptr_guard() {
+ std::free(ptr);
+ }
+
+ T *ptr;
+};
+
+template<typename T>
+auto construct = std::views::transform([] (auto &&value) {
+ return T(std::forward<decltype(value)>(value));
+});
+
+} // namespace bsd::__detail
+
+#endif /* !_NVXX_UTIL_H_INCLUDED */