···11+// Copyright 2021, Collabora, Ltd.
22+// SPDX-License-Identifier: BSL-1.0
33+/*!
44+ * @file
55+ * @brief A collection of strings, like a list of extensions to enable
66+ *
77+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
88+ * @ingroup aux_util
99+ *
1010+ */
1111+#pragma once
1212+1313+#include <stdint.h>
1414+1515+#ifdef __cplusplus
1616+extern "C" {
1717+#endif
1818+1919+2020+/*!
2121+ * @brief A collection of string literals (const char *), such as used for extension name lists.
2222+ *
2323+ * @see xrt::auxiliary::util::StringList
2424+ */
2525+struct u_string_list;
2626+2727+/*!
2828+ * @brief Create a string list with room for at least the given number of strings.
2929+ *
3030+ * @public @memberof u_string_list
3131+ */
3232+struct u_string_list *
3333+u_string_list_create(void);
3434+3535+/*!
3636+ * @brief Create a string list with room for at least the given number of strings.
3737+ *
3838+ * @public @memberof u_string_list
3939+ */
4040+struct u_string_list *
4141+u_string_list_create_with_capacity(uint32_t capacity);
4242+4343+/*!
4444+ * @brief Retrieve the number of elements in the list
4545+ *
4646+ * @public @memberof u_string_list
4747+ */
4848+uint32_t
4949+u_string_list_get_size(const struct u_string_list *usl);
5050+5151+/*!
5252+ * @brief Retrieve the data pointer of the list
5353+ *
5454+ * @public @memberof u_string_list
5555+ */
5656+const char *const *
5757+u_string_list_get_data(const struct u_string_list *usl);
5858+5959+/*!
6060+ * @brief Append a new string literal to the list.
6161+ *
6262+ * @param usl self pointer
6363+ * @param str a non-null, null-terminated string that must live at least as long as the list, preferably a string
6464+ * literal.
6565+ * @return 1 if successfully added, negative for errors.
6666+ *
6767+ * @public @memberof u_string_list
6868+ */
6969+int
7070+u_string_list_append(struct u_string_list *usl, const char *str);
7171+7272+/*!
7373+ * @brief Append a new string literal to the list, if it's not the same as a string already in the list.
7474+ *
7575+ * (Comparing string contents, not just pointers)
7676+ *
7777+ * @param usl self pointer
7878+ * @param str a non-null, null-terminated string that must live at least as long as the list, preferably a string
7979+ * literal.
8080+ * @return 1 if successfully added, 0 if already existing so not added, negative for errors.
8181+ *
8282+ * @public @memberof u_string_list
8383+ */
8484+int
8585+u_string_list_append_unique(struct u_string_list *usl, const char *str);
8686+8787+/*!
8888+ * @brief Destroy a string list.
8989+ *
9090+ * Performs null checks and sets your pointer to zero.
9191+ *
9292+ * @public @memberof u_string_list
9393+ */
9494+void
9595+u_string_list_destroy(struct u_string_list **list_ptr);
9696+9797+#ifdef __cplusplus
9898+} // extern "C"
9999+#endif
+148
src/xrt/auxiliary/util/u_string_list.hpp
···11+// Copyright 2021, Collabora, Ltd.
22+// SPDX-License-Identifier: BSL-1.0
33+/*!
44+ * @file
55+ * @brief A collection of strings, like a list of extensions to enable
66+ *
77+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
88+ * @ingroup aux_util
99+ *
1010+ */
1111+1212+#pragma once
1313+1414+#include "u_string_list.h"
1515+1616+#include <memory>
1717+#include <vector>
1818+#include <limits>
1919+#include <stdexcept>
2020+#include <string>
2121+#include <algorithm>
2222+2323+namespace xrt::auxiliary::util {
2424+2525+/*!
2626+ * @brief A collection of strings (const char *), like a list of extensions to enable.
2727+ *
2828+ * This version is only for use with strings that will outlive this object, preferably string literals.
2929+ *
3030+ * Size is limited to one less than the max value of uint32_t which shouldn't be a problem,
3131+ * the size really should be much smaller (especially if you use push_back_unique()).
3232+ */
3333+class StringList
3434+{
3535+public:
3636+ /// Construct a string list.
3737+ StringList() = default;
3838+ /// Construct a string list with the given capacity.
3939+ StringList(uint32_t capacity) : vec(capacity, nullptr)
4040+ {
4141+ // best way I know to create with capacity
4242+ vec.clear();
4343+ }
4444+ StringList(StringList &&) = default;
4545+ StringList(StringList const &) = default;
4646+4747+ StringList &
4848+ operator=(StringList &&) = default;
4949+ StringList &
5050+ operator=(StringList const &) = default;
5151+5252+ /// Construct a string list with the given items
5353+ template <uint32_t N> StringList(const char *(&arr)[N]) : StringList(N)
5454+ {
5555+ for (auto &&elt : arr) {
5656+ push_back(elt);
5757+ }
5858+ }
5959+6060+ /*!
6161+ * @brief Get the size of the array (the number of strings)
6262+ */
6363+ uint32_t
6464+ size() const noexcept
6565+ {
6666+ return static_cast<uint32_t>(vec.size());
6767+ }
6868+6969+ /*!
7070+ * @brief Get the data pointer of the array
7171+ */
7272+ const char *const *
7373+ data() const noexcept
7474+ {
7575+ return vec.data();
7676+ }
7777+7878+ /*!
7979+ * @brief Append a new string to the list.
8080+ *
8181+ * @param str a non-null, null-terminated string that must live at least as long as the list,
8282+ * preferably a string literal.
8383+ *
8484+ * @throws std::out_of_range if you have a ridiculous number of strings in your list already,
8585+ * std::invalid_argument if you pass a null pointer.
8686+ */
8787+ void
8888+ push_back(const char *str)
8989+ {
9090+9191+ if (vec.size() > std::numeric_limits<uint32_t>::max() - 1) {
9292+ throw std::out_of_range("Size limit reached");
9393+ }
9494+ if (str == nullptr) {
9595+ throw std::invalid_argument("Cannot pass a null pointer");
9696+ }
9797+ vec.push_back(str);
9898+ }
9999+100100+ /// Add all given items
101101+ /// @throws the same as what push_back() throws
102102+ template <uint32_t N>
103103+ void
104104+ push_back_all(const char *(&arr)[N])
105105+ {
106106+ for (auto &&elt : arr) {
107107+ push_back(elt);
108108+ }
109109+ }
110110+ /*!
111111+ * @brief Append a new string to the list if it doesn't match any existing string.
112112+ *
113113+ * (Comparing string contents, not just pointers)
114114+ *
115115+ * This does a simple linear search, because it is assumed that the size of this list is fairly small.
116116+ *
117117+ * @param str a non-null, null-terminated string that must live at least as long as the list,
118118+ * preferably a string literal.
119119+ *
120120+ * @return true if we added it
121121+ *
122122+ * @throws std::out_of_range if you have a ridiculous number of strings in your list already,
123123+ * std::invalid_argument if you pass a null pointer.
124124+ */
125125+ bool
126126+ push_back_unique(const char *str)
127127+ {
128128+ if (vec.size() > std::numeric_limits<uint32_t>::max() - 1) {
129129+ throw std::out_of_range("Size limit reached");
130130+ }
131131+ if (str == nullptr) {
132132+ throw std::invalid_argument("Cannot pass a null pointer");
133133+ }
134134+ std::string needle{str};
135135+ auto it = std::find_if(vec.begin(), vec.end(), [needle](const char *elt) { return needle == elt; });
136136+ if (it != vec.end()) {
137137+ // already have it
138138+ return false;
139139+ }
140140+ vec.push_back(str);
141141+ return true;
142142+ }
143143+144144+private:
145145+ std::vector<const char *> vec;
146146+};
147147+148148+} // namespace xrt::auxiliary::util