a/util: Add utility for lists of strings, like extension lists.

This commit is contained in:
Ryan Pavlik 2021-11-05 12:45:36 -05:00 committed by Jakob Bornecrantz
parent ea38309c86
commit 27a8ec675b
4 changed files with 363 additions and 0 deletions

View file

@ -183,6 +183,9 @@ add_library(
util/u_sink_queue.c
util/u_sink_quirk.c
util/u_sink_split.c
util/u_string_list.cpp
util/u_string_list.h
util/u_string_list.hpp
util/u_template_historybuf.hpp
util/u_time.cpp
util/u_time.h

View file

@ -0,0 +1,113 @@
// Copyright 2021, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings, like a list of extensions to enable
*
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#include "u_string_list.h"
#include "u_string_list.hpp"
using xrt::auxiliary::util::StringList;
struct u_string_list
{
u_string_list() = default;
u_string_list(StringList &&sl) : list(std::move(sl)) {}
StringList list;
};
struct u_string_list *
u_string_list_create()
{
try {
auto ret = std::make_unique<u_string_list>();
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
struct u_string_list *
u_string_list_create_with_capacity(uint32_t capacity)
{
try {
auto ret = std::make_unique<u_string_list>(xrt::auxiliary::util::StringList{capacity});
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
uint32_t
u_string_list_get_size(const struct u_string_list *usl)
{
if (usl == nullptr) {
return 0;
}
return usl->list.size();
}
const char *const *
u_string_list_get_data(const struct u_string_list *usl)
{
if (usl == nullptr) {
return nullptr;
}
return usl->list.data();
}
int
u_string_list_append(struct u_string_list *usl, const char *str)
{
if (usl == nullptr) {
return -1;
}
try {
usl->list.push_back(str);
return 1;
} catch (std::exception const &) {
return -1;
}
}
int
u_string_list_append_unique(struct u_string_list *usl, const char *str)
{
if (usl == nullptr) {
return -1;
}
try {
auto added = usl->list.push_back_unique(str);
return added ? 1 : 0;
} catch (std::exception const &) {
return -1;
}
}
void
u_string_list_destroy(struct u_string_list **list_ptr)
{
if (list_ptr == nullptr) {
return;
}
u_string_list *list = *list_ptr;
if (list == nullptr) {
return;
}
delete list;
*list_ptr = nullptr;
}

View file

@ -0,0 +1,99 @@
// Copyright 2021, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings, like a list of extensions to enable
*
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @brief A collection of string literals (const char *), such as used for extension name lists.
*
* @see xrt::auxiliary::util::StringList
*/
struct u_string_list;
/*!
* @brief Create a string list with room for at least the given number of strings.
*
* @public @memberof u_string_list
*/
struct u_string_list *
u_string_list_create(void);
/*!
* @brief Create a string list with room for at least the given number of strings.
*
* @public @memberof u_string_list
*/
struct u_string_list *
u_string_list_create_with_capacity(uint32_t capacity);
/*!
* @brief Retrieve the number of elements in the list
*
* @public @memberof u_string_list
*/
uint32_t
u_string_list_get_size(const struct u_string_list *usl);
/*!
* @brief Retrieve the data pointer of the list
*
* @public @memberof u_string_list
*/
const char *const *
u_string_list_get_data(const struct u_string_list *usl);
/*!
* @brief Append a new string literal to the list.
*
* @param usl self pointer
* @param str a non-null, null-terminated string that must live at least as long as the list, preferably a string
* literal.
* @return 1 if successfully added, negative for errors.
*
* @public @memberof u_string_list
*/
int
u_string_list_append(struct u_string_list *usl, const char *str);
/*!
* @brief Append a new string literal to the list, if it's not the same as a string already in the list.
*
* (Comparing string contents, not just pointers)
*
* @param usl self pointer
* @param str a non-null, null-terminated string that must live at least as long as the list, preferably a string
* literal.
* @return 1 if successfully added, 0 if already existing so not added, negative for errors.
*
* @public @memberof u_string_list
*/
int
u_string_list_append_unique(struct u_string_list *usl, const char *str);
/*!
* @brief Destroy a string list.
*
* Performs null checks and sets your pointer to zero.
*
* @public @memberof u_string_list
*/
void
u_string_list_destroy(struct u_string_list **list_ptr);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -0,0 +1,148 @@
// Copyright 2021, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings, like a list of extensions to enable
*
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#pragma once
#include "u_string_list.h"
#include <memory>
#include <vector>
#include <limits>
#include <stdexcept>
#include <string>
#include <algorithm>
namespace xrt::auxiliary::util {
/*!
* @brief A collection of strings (const char *), like a list of extensions to enable.
*
* This version is only for use with strings that will outlive this object, preferably string literals.
*
* Size is limited to one less than the max value of uint32_t which shouldn't be a problem,
* the size really should be much smaller (especially if you use push_back_unique()).
*/
class StringList
{
public:
/// Construct a string list.
StringList() = default;
/// Construct a string list with the given capacity.
StringList(uint32_t capacity) : vec(capacity, nullptr)
{
// best way I know to create with capacity
vec.clear();
}
StringList(StringList &&) = default;
StringList(StringList const &) = default;
StringList &
operator=(StringList &&) = default;
StringList &
operator=(StringList const &) = default;
/// Construct a string list with the given items
template <uint32_t N> StringList(const char *(&arr)[N]) : StringList(N)
{
for (auto &&elt : arr) {
push_back(elt);
}
}
/*!
* @brief Get the size of the array (the number of strings)
*/
uint32_t
size() const noexcept
{
return static_cast<uint32_t>(vec.size());
}
/*!
* @brief Get the data pointer of the array
*/
const char *const *
data() const noexcept
{
return vec.data();
}
/*!
* @brief Append a new string to the list.
*
* @param str a non-null, null-terminated string that must live at least as long as the list,
* preferably a string literal.
*
* @throws std::out_of_range if you have a ridiculous number of strings in your list already,
* std::invalid_argument if you pass a null pointer.
*/
void
push_back(const char *str)
{
if (vec.size() > std::numeric_limits<uint32_t>::max() - 1) {
throw std::out_of_range("Size limit reached");
}
if (str == nullptr) {
throw std::invalid_argument("Cannot pass a null pointer");
}
vec.push_back(str);
}
/// Add all given items
/// @throws the same as what push_back() throws
template <uint32_t N>
void
push_back_all(const char *(&arr)[N])
{
for (auto &&elt : arr) {
push_back(elt);
}
}
/*!
* @brief Append a new string to the list if it doesn't match any existing string.
*
* (Comparing string contents, not just pointers)
*
* This does a simple linear search, because it is assumed that the size of this list is fairly small.
*
* @param str a non-null, null-terminated string that must live at least as long as the list,
* preferably a string literal.
*
* @return true if we added it
*
* @throws std::out_of_range if you have a ridiculous number of strings in your list already,
* std::invalid_argument if you pass a null pointer.
*/
bool
push_back_unique(const char *str)
{
if (vec.size() > std::numeric_limits<uint32_t>::max() - 1) {
throw std::out_of_range("Size limit reached");
}
if (str == nullptr) {
throw std::invalid_argument("Cannot pass a null pointer");
}
std::string needle{str};
auto it = std::find_if(vec.begin(), vec.end(), [needle](const char *elt) { return needle == elt; });
if (it != vec.end()) {
// already have it
return false;
}
vec.push_back(str);
return true;
}
private:
std::vector<const char *> vec;
};
} // namespace xrt::auxiliary::util