Files
RetroArch/libretro-common/include/lists/string_list.h
T
Arnold de Ruiterandlibretroadmin e337babce9 core_info: read an info file added after its core was cached, keep served entries in a rewritten cache (#20007)
* Fix core info cache ignoring late .info files and dropping cached entries on rewrite

* core_info: write the cache straight from the core list

The cache writer takes the core list's entries as they are instead of
a deep copy of every installed core, and a core read from its info
file no longer gets copied into a cache list that is not written.

core_info_cache_test also checks that an unchanged core set leaves the
cache alone, and runs under ASan and UBSan in Linux-samples-tasks.

* core_info: read cached entries in place, take core paths from the listing

The cache reader parses each entry straight into the next slot of the
cache list instead of a separate allocation moved in afterwards, and a
firmware list grows geometrically rather than one entry per realloc.
A core's path is taken over from the directory listing, which is freed
at the end of the same pass, instead of being copied.

core_info_cache_test adds a start served from the cache alone, with
more cores than the list starts with and long firmware lists, and a
cache cut off inside an entry, which must be discarded without a leak.

* string_list: add packed splits, use them for core info lists

string_split_packed() splits into a single allocation holding the
list, its elements and the tokens, marked by cap 0 with elements
present. string_list_free() releases it in one free; growing it and
string_list_deinitialize() are refused, so a packed list stays
read-only.

Every pipe-separated core info field is split this way, from the
cache and from info files alike, which takes a warm start over the
full libretro-core-info set from 16661 allocations to 8851. The
string_split_packed sample checks it against string_split and the
refusals, under ASan and UBSan and as a mingw-w64 build under Wine.

---------

Co-authored-by: libretroadmin <[email protected]>
2026-11-06 14:16:58 +01:00

212 lines
6.5 KiB
C

/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (string_list.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* 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 OR COPYRIGHT HOLDERS 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 __LIBRETRO_SDK_STRING_LIST_H
#define __LIBRETRO_SDK_STRING_LIST_H
#include <retro_common_api.h>
#include <boolean.h>
#include <stdlib.h>
#include <stddef.h>
RETRO_BEGIN_DECLS
union string_list_elem_attr
{
bool b;
int i;
void *p;
};
struct string_list_elem
{
char *data;
void *userdata;
union string_list_elem_attr attr;
};
struct string_list
{
struct string_list_elem *elems;
size_t size;
size_t cap;
};
/**
* string_list_find_elem:
* @list : pointer to string list
* @elem : element to find inside the string list.
*
* Searches for an element (@elem) inside the string list.
*
* @return 1-based index if element could be found, otherwise 0.
*/
int string_list_find_elem(const struct string_list *list, const char *elem);
/**
* string_list_find_elem_prefix:
* @list : pointer to string list
* @prefix : prefix to append to @elem
* @elem : element to find inside the string list.
*
* Searches for an element (@elem) inside the string list. Will
* also search for the same element prefixed by @prefix.
*
* Returns: true (1) if element could be found, otherwise false (0).
*/
bool string_list_find_elem_prefix(const struct string_list *list,
const char *prefix, const char *elem);
/**
* string_split:
* @str : string to turn into a string list
* @delim : delimiter character to use for splitting the string.
*
* Creates a new string list based on string @str, delimited by @delim.
*
* Returns: new string list if successful, otherwise NULL.
*/
struct string_list *string_split(const char *str, const char *delim);
/**
* string_split_packed:
* @str : string to split
* @delim : delimiter characters
*
* Like string_split(), in one allocation holding the list, its
* elements and the tokens. The list is read-only: it cannot grow,
* and string_list_deinitialize() refuses it. Free it with
* string_list_free(). A packed list has cap 0 and non-NULL elems.
*
* @return the list, or NULL on allocation failure.
*/
struct string_list *string_split_packed(const char *str, const char *delim);
bool string_split_noalloc(struct string_list *list,
const char *str, const char *delim);
bool string_list_deinitialize(struct string_list *list);
bool string_list_initialize(struct string_list *list);
/**
* string_list_new:
*
* Creates a new string list. Has to be freed manually.
*
* @return New string list if successful, otherwise NULL.
**/
struct string_list *string_list_new(void);
/**
* string_list_append:
* @list : pointer to string list
* @elem : element to add to the string list
* @attr : attributes of new element.
*
* Appends a new element to the string list.
*
* Hidden non-leaf function cost:
* - Calls string_list_capacity()
* - Calls strdup
*
* @return true if successful, otherwise false.
**/
bool string_list_append(struct string_list *list, const char *elem,
union string_list_elem_attr attr);
/**
* string_list_append_n:
* @list : pointer to string list
* @elem : element to add to the string list
* @len : length of @elem (caller already knows it)
* @attr : attributes of new element.
*
* Appends a new element when the caller already has its length,
* avoiding a redundant strlen inside strdup.
*
* @return true if successful, otherwise false.
**/
bool string_list_append_n(struct string_list *list, const char *elem,
size_t len, union string_list_elem_attr attr);
/**
* string_list_free
* @list : pointer to string list object
*
* Frees a string list.
**/
void string_list_free(struct string_list *list);
/**
* string_list_join_concat:
* @s : buffer that @list will be joined to.
* @len : length of @s.
* @list : pointer to string list.
* @delim : delimiter character for @list.
*
* A string list will be joined/concatenated as a
* string to @s, delimited by @delim.
*
* NOTE: @s must be NULL-terminated.
*
* Hidden non-leaf function cost:
* - Calls strlen()
* - Calls strlcpy x times in a loop
**/
void string_list_join_concat(char *s, size_t len,
const struct string_list *list, const char *sep);
/**
* string_list_join_concat_special:
* @s : buffer that @list will be joined to.
* @len : length of @s.
* @list : pointer to string list.
* @delim : delimiter character for @list.
*
* Specialized version of string_list_join_concat
* without the bounds check.
*
* A string list will be joined/concatenated as a
* string to @s, delimited by @delim.
**/
void string_list_join_concat_special(char *s, size_t len,
const struct string_list *list, const char *delim);
/**
* string_list_capacity:
* @list : pointer to string list
* @cap : new capacity for string list.
*
* Change maximum capacity of string list's size.
*
* @return true if successful, otherwise false.
**/
bool string_list_capacity(struct string_list *list, size_t cap);
struct string_list *string_list_clone(const struct string_list *src);
RETRO_END_DECLS
#endif