mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
* 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]>
212 lines
6.5 KiB
C
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
|