aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--libnvxx/Makefile2
-rw-r--r--libnvxx/nvxx.h1
-rw-r--r--libnvxx/nvxx_iterator.cc157
-rw-r--r--libnvxx/nvxx_iterator.h99
-rw-r--r--libnvxx/tests/Makefile2
-rw-r--r--libnvxx/tests/nvxx_iterator.cc78
7 files changed, 338 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 3d00a1e..9da6e2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@
.depend*
Kyuafile
/libnvxx/tests/nvxx_basic
+/libnvxx/tests/nvxx_iterator
diff --git a/libnvxx/Makefile b/libnvxx/Makefile
index d201992..966b4db 100644
--- a/libnvxx/Makefile
+++ b/libnvxx/Makefile
@@ -26,7 +26,7 @@ LIBDIR= ${PREFIX}/lib
INCLUDEDIR= ${PREFIX}/include
SHLIB_MAJOR= 1
INCS= nvxx.h nvxx_base.h
-SRCS= nvxx.cc
+SRCS= nvxx.cc nvxx_iterator.cc
CXXSTD= c++23
CXXFLAGS+= -W -Wall -Wextra -Werror
LDADD= -lnv
diff --git a/libnvxx/nvxx.h b/libnvxx/nvxx.h
index 7c938ce..85eb684 100644
--- a/libnvxx/nvxx.h
+++ b/libnvxx/nvxx.h
@@ -28,5 +28,6 @@
*/
#include "nvxx_base.h"
+#include "nvxx_iterator.h"
#endif /* !_NVXX_H_INCLUDED */
diff --git a/libnvxx/nvxx_iterator.cc b/libnvxx/nvxx_iterator.cc
new file mode 100644
index 0000000..5a8f04f
--- /dev/null
+++ b/libnvxx/nvxx_iterator.cc
@@ -0,0 +1,157 @@
+/*
+ * 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 <sys/cnv.h>
+
+#include "nvxx.h"
+
+namespace bsd {
+
+nv_list_iterator
+begin(const_nv_list const &nvl)
+{
+ return nv_list_iterator(nvl);
+}
+
+nv_list_iterator
+begin(nv_list const &nvl)
+{
+ return nv_list_iterator(nvl);
+}
+
+std::default_sentinel_t
+end(const_nv_list const &)
+{
+ return {};
+}
+
+std::default_sentinel_t
+end(nv_list const &)
+{
+ return {};
+}
+
+nv_list_iterator::nv_list_iterator()
+{
+}
+
+nv_list_iterator::nv_list_iterator(const_nv_list const &nvl)
+ : __nvlist(nvl.ptr())
+{
+ __advance();
+}
+
+nv_list_iterator::nv_list_iterator(nv_list const &nvl)
+ : __nvlist(nvl.ptr())
+{
+ __advance();
+}
+
+nv_list_iterator &
+nv_list_iterator::operator++()
+{
+ __advance();
+ return *this;
+}
+
+nv_list_iterator
+nv_list_iterator::operator++(int)
+{
+ nv_list_iterator tmp = *this;
+ ++(*this);
+ return tmp;
+}
+
+bool
+nv_list_iterator::operator==(nv_list_iterator const &other) const
+{
+ return (__nvlist == other.__nvlist)
+ && (__cookie == other.__cookie);
+}
+
+bool
+nv_list_iterator::operator==(std::default_sentinel_t) const
+{
+ return __cookie == nullptr;
+}
+
+nv_list_iterator::const_reference
+nv_list_iterator::operator*() const
+{
+ return __current;
+}
+
+nv_list_iterator::const_pointer
+nv_list_iterator::operator->() const
+{
+ return &__current;
+}
+
+void
+nv_list_iterator::__advance()
+{
+ auto type = int{};
+ auto const *namep = ::nvlist_next(__nvlist, &type, &__cookie);
+
+ if (namep == nullptr) {
+ __cookie = nullptr;
+ return;
+ }
+
+ auto name = std::string_view(namep);
+
+ switch (type) {
+ case NV_TYPE_NULL:
+ __current = std::make_pair(name, nullptr);
+ break;
+ case NV_TYPE_BOOL:
+ __current = std::make_pair(name, cnvlist_get_bool(__cookie));
+ break;
+ case NV_TYPE_NUMBER:
+ __current = std::make_pair(name, cnvlist_get_number(__cookie));
+ break;
+ case NV_TYPE_STRING:
+ __current = std::make_pair(name,
+ std::string_view(
+ cnvlist_get_string(__cookie)));
+ break;
+ case NV_TYPE_NVLIST:
+ __current = std::make_pair(name,
+ const_nv_list(cnvlist_get_nvlist(__cookie)));
+ break;
+ case NV_TYPE_DESCRIPTOR:
+ __current = std::make_pair(name,
+ cnvlist_get_descriptor(__cookie));
+ break;
+ case NV_TYPE_BINARY: {
+ auto nitems = std::size_t{};
+ auto ptr = cnvlist_get_binary(__cookie, &nitems);
+ auto span = std::span{static_cast<std::byte const *>(ptr), nitems};
+ __current = std::make_pair(name, span);
+ break;
+ }
+ default:
+ std::abort();
+ }
+}
+
+}
diff --git a/libnvxx/nvxx_iterator.h b/libnvxx/nvxx_iterator.h
new file mode 100644
index 0000000..d626bfd
--- /dev/null
+++ b/libnvxx/nvxx_iterator.h
@@ -0,0 +1,99 @@
+/*
+ * 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_ITERATOR_H_INCLUDED
+#define _NVXX_ITERATOR_H_INCLUDED
+
+#include <variant>
+#include <iterator>
+#include <concepts>
+
+/*
+ * iterator support for libnvxx. this exposes a const_nv_list as an iterable
+ * container or range.
+ */
+
+namespace bsd {
+
+// the key type of an nvlist value
+using nv_list_key_t = std::string_view;
+
+// the value type of an nvlist value
+using nv_list_value_t = std::variant<
+ nullptr_t, /* null */
+ bool, /* bool */
+ std::uint64_t, /* number */
+ std::string_view, /* string */
+ const_nv_list, /* nvlist */
+ int, /* descriptor */
+ std::span<std::byte const> /* binary */
+>;
+
+// the iterator value type
+using nv_list_pair_t = std::pair<nv_list_key_t, nv_list_value_t>;
+
+/*
+ * The nvlist iterator type. This is never an 'end' iterator, because we use
+ * a sentinel for that.
+ */
+struct nv_list_iterator {
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+ using value_type = nv_list_pair_t;
+ using pointer = value_type *;
+ using const_pointer = value_type const *;
+ using reference = value_type &;
+ using const_reference = value_type const &;
+ using sentinel = std::default_sentinel_t;
+
+ nv_list_iterator();
+ explicit nv_list_iterator(const_nv_list const &nvl);
+ explicit nv_list_iterator(nv_list const &nvl);
+
+ nv_list_iterator &operator++();
+ nv_list_iterator operator++(int);
+
+ bool operator==(nv_list_iterator const &other) const;
+ bool operator==(std::default_sentinel_t) const;
+
+ const_reference operator*() const;
+ const_pointer operator->() const;
+
+private:
+ ::nvlist_t const *__nvlist = nullptr;
+ void *__cookie = nullptr;
+ nv_list_pair_t __current;
+
+ void __advance();
+};
+
+static_assert(std::forward_iterator<nv_list_iterator>);
+static_assert(std::sentinel_for<std::default_sentinel_t, nv_list_iterator>);
+
+nv_list_iterator begin(const_nv_list const &nvl);
+nv_list_iterator begin(nv_list const &nvl);
+std::default_sentinel_t end(const_nv_list const &);
+std::default_sentinel_t end(nv_list const &);
+
+};
+
+#endif /* !_NVXX_ITERATOR_H_INCLUDED */
diff --git a/libnvxx/tests/Makefile b/libnvxx/tests/Makefile
index 29d0351..db4b538 100644
--- a/libnvxx/tests/Makefile
+++ b/libnvxx/tests/Makefile
@@ -20,7 +20,7 @@
PREFIX?= /usr/local
TESTSDIR?= ${PREFIX}/tests/nvxx
-ATF_TESTS_CXX= nvxx_basic
+ATF_TESTS_CXX= nvxx_basic nvxx_iterator
CXXSTD= c++23
# Note that we can't use -Werror here because it breaks ATF.
CXXFLAGS+= -W -Wall -Wextra
diff --git a/libnvxx/tests/nvxx_iterator.cc b/libnvxx/tests/nvxx_iterator.cc
new file mode 100644
index 0000000..df78bdf
--- /dev/null
+++ b/libnvxx/tests/nvxx_iterator.cc
@@ -0,0 +1,78 @@
+/*
+ * 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 <algorithm>
+#include <ranges>
+#include <list>
+#include <vector>
+#include <span>
+#include <string>
+#include <string_view>
+
+#include <atf-c++.hpp>
+
+#include "nvxx.h"
+
+#define TEST_CASE(name) \
+ ATF_TEST_CASE_WITHOUT_HEAD(name) \
+ ATF_TEST_CASE_BODY(name)
+
+TEST_CASE(nvxx_basic_iterate)
+{
+ using namespace std::literals;
+ auto nvl = bsd::nv_list();
+
+ nvl.add_number("a number", 42);
+ nvl.add_string("a string", "a test string");
+ nvl.add_bool("a bool", true);
+
+ auto begin = std::ranges::begin(nvl);
+ auto end = std::ranges::end(nvl);
+
+ auto i = 0u;
+ while (begin != end) {
+ auto name = begin->first;
+ auto const &value = begin->second;
+
+ if (std::holds_alternative<std::uint64_t>(value)) {
+ ATF_REQUIRE_EQ("a number"sv, name);
+ ATF_REQUIRE_EQ(42, std::get<std::uint64_t>(value));
+ } else if (std::holds_alternative<std::string_view>(value)) {
+ ATF_REQUIRE_EQ("a string"sv, name);
+ ATF_REQUIRE_EQ("a test string",
+ std::get<std::string_view>(value));
+ } else if (std::holds_alternative<bool>(value)) {
+ ATF_REQUIRE_EQ("a bool"sv, name);
+ ATF_REQUIRE_EQ(true, std::get<bool>(value));
+ } else
+ ATF_REQUIRE_EQ(true, false);
+
+ ++i;
+ ++begin;
+ }
+ ATF_REQUIRE_EQ(3, i);
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, nvxx_basic_iterate);
+}