playlist: pack an entry's slot, runtime status and thumbnail flags

The three ride in one word: the slot index is a subsystem content
slot, the runtime status has three values, and the thumbnail flags
are five bits. struct playlist_entry goes from 120 bytes to 112, so
a large playlist sheds another eighty kilobytes on top of what the
timestamps returned.

The JSON reader gains one more name for the slot, since a packed
field has no address to hand it.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-09-12 11:07:32 +02:00
1 parent 5599a3176b
commit 60cb421bc0
10 files changed
+61 -36

No files matched your search

+1 -1
View File
@@ -1870,7 +1870,7 @@ void manual_content_scan_add_content_to_playlist(
entry.core_name = (char*)FILE_PATH_DETECT;
entry.crc32 = (char*)"00000000|crc";
entry.db_name = task_config->database_name;
entry.entry_slot = 0;
PLAYLIST_SET_ENTRY_SLOT(&entry, 0);
/* Add entry to playlist */
playlist_push(playlist, &entry);
+2 -2
View File
@@ -1275,11 +1275,11 @@ static int action_bind_sublabel_playlist_entry(
return 0;
/* Check whether runtime info should be loaded from log file */
if (entry->runtime_status == PLAYLIST_RUNTIME_UNKNOWN)
if (PLAYLIST_RUNTIME_STATUS(entry) == PLAYLIST_RUNTIME_UNKNOWN)
runtime_update_playlist(playlist, playlist_index);
/* Check whether runtime info is valid */
if (entry->runtime_status == PLAYLIST_RUNTIME_VALID)
if (PLAYLIST_RUNTIME_STATUS(entry) == PLAYLIST_RUNTIME_VALID)
{
size_t n = 0;
char tmp[128];
+1 -1
View File
@@ -4234,7 +4234,7 @@ static bool materialui_render_process_entry_playlist_desktop(
/* Get runtime info, if available */
if (content_runtime_log || content_runtime_log_aggregate)
{
if (entry->runtime_status == PLAYLIST_RUNTIME_UNKNOWN)
if (PLAYLIST_RUNTIME_STATUS(entry) == PLAYLIST_RUNTIME_UNKNOWN)
runtime_update_playlist(mui->playlist, playlist_idx);
if (entry->runtime_str && *entry->runtime_str)
+1 -1
View File
@@ -4659,7 +4659,7 @@ static void ozone_update_content_metadata(ozone_handle_t *ozone)
if (entry)
{
if ( (entry->runtime_status == PLAYLIST_RUNTIME_UNKNOWN)
if ( (PLAYLIST_RUNTIME_STATUS(entry) == PLAYLIST_RUNTIME_UNKNOWN)
|| (ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU))
runtime_update_playlist(playlist, playlist_index);
+27 -18
View File
@@ -120,6 +120,7 @@ enum json_ctx_flags
enum playlist_json_packed_val
{
PLAYLIST_JSON_PACKED_NONE = 0,
PLAYLIST_JSON_PACKED_ENTRY_SLOT,
PLAYLIST_JSON_PACKED_RUNTIME_HOURS,
PLAYLIST_JSON_PACKED_RUNTIME_MINUTES,
PLAYLIST_JSON_PACKED_RUNTIME_SECONDS,
@@ -686,8 +687,8 @@ static void playlist_free_entry(struct playlist_entry *entry)
entry->last_played_str = NULL;
entry->subsystem_roms = NULL;
entry->path_id = NULL;
entry->entry_slot = 0;
entry->runtime_status = PLAYLIST_RUNTIME_UNKNOWN;
PLAYLIST_SET_ENTRY_SLOT(entry, 0);
PLAYLIST_SET_RUNTIME_STATUS(entry, PLAYLIST_RUNTIME_UNKNOWN);
PLAYLIST_SET_RUNTIME_HOURS(entry, 0);
PLAYLIST_SET_RUNTIME_MINUTES(entry, 0);
PLAYLIST_SET_RUNTIME_SECONDS(entry, 0);
@@ -1211,9 +1212,9 @@ void playlist_update_runtime(playlist_t *playlist, size_t idx,
playlist->flags |= CNT_PLAYLIST_FLG_MOD;
}
if (update_entry->runtime_status != entry->runtime_status)
if (PLAYLIST_RUNTIME_STATUS(update_entry) != PLAYLIST_RUNTIME_STATUS(entry))
{
entry->runtime_status = update_entry->runtime_status;
PLAYLIST_SET_RUNTIME_STATUS(entry, PLAYLIST_RUNTIME_STATUS(update_entry));
if (register_update)
playlist->flags |= CNT_PLAYLIST_FLG_MOD;
}
@@ -1399,7 +1400,8 @@ bool playlist_push_runtime(playlist_t *playlist,
if (*real_core_path)
playlist->entries[0].core_path = strdup(real_core_path);
playlist->entries[0].runtime_status = entry->runtime_status;
PLAYLIST_SET_RUNTIME_STATUS(&playlist->entries[0],
PLAYLIST_RUNTIME_STATUS(entry));
PLAYLIST_SET_RUNTIME_HOURS(&playlist->entries[0], PLAYLIST_RUNTIME_HOURS(entry));
PLAYLIST_SET_RUNTIME_MINUTES(&playlist->entries[0], PLAYLIST_RUNTIME_MINUTES(entry));
PLAYLIST_SET_RUNTIME_SECONDS(&playlist->entries[0], PLAYLIST_RUNTIME_SECONDS(entry));
@@ -1437,7 +1439,7 @@ void playlist_update_thumbnail_name_flag(playlist_t *playlist, size_t idx,
return;
entry = &playlist->entries[idx];
entry->thumbnail_flags |= thumbnail_flags;
PLAYLIST_OR_THUMBNAIL_FLAGS(entry, thumbnail_flags);
}
enum playlist_thumbnail_name_flags playlist_get_curr_thumbnail_name_flag(playlist_t *playlist, size_t idx)
@@ -1446,7 +1448,7 @@ enum playlist_thumbnail_name_flags playlist_get_curr_thumbnail_name_flag(playlis
if (!playlist || idx >= RBUF_LEN(playlist->entries))
return PLAYLIST_THUMBNAIL_FLAG_NONE;
entry = &playlist->entries[idx];
return (enum playlist_thumbnail_name_flags)entry->thumbnail_flags;
return (enum playlist_thumbnail_name_flags)PLAYLIST_THUMBNAIL_FLAGS(entry);
}
@@ -1458,11 +1460,11 @@ enum playlist_thumbnail_name_flags playlist_get_next_thumbnail_name_flag(playlis
return PLAYLIST_THUMBNAIL_FLAG_NONE;
entry = (struct playlist_entry*)&playlist->entries[idx];
if (entry->thumbnail_flags & PLAYLIST_THUMBNAIL_FLAG_SHORT_NAME)
if (PLAYLIST_THUMBNAIL_FLAGS(entry) & PLAYLIST_THUMBNAIL_FLAG_SHORT_NAME)
return PLAYLIST_THUMBNAIL_FLAG_NONE;
if (entry->thumbnail_flags & PLAYLIST_THUMBNAIL_FLAG_STD_NAME)
if (PLAYLIST_THUMBNAIL_FLAGS(entry) & PLAYLIST_THUMBNAIL_FLAG_STD_NAME)
return PLAYLIST_THUMBNAIL_FLAG_SHORT_NAME;
if (entry->thumbnail_flags & PLAYLIST_THUMBNAIL_FLAG_FULL_NAME)
if (PLAYLIST_THUMBNAIL_FLAGS(entry) & PLAYLIST_THUMBNAIL_FLAG_FULL_NAME)
return PLAYLIST_THUMBNAIL_FLAG_STD_NAME;
/* Special case: only one entry in playlist, only one query is possible
* as flag swapping relies on going back and forth among entries
@@ -1735,7 +1737,8 @@ static bool playlist_push_new_entry(playlist_t *playlist,
playlist->entries[0].last_played_str = NULL;
playlist->entries[0].subsystem_roms = NULL;
playlist->entries[0].path_id = NULL;
playlist->entries[0].runtime_status = PLAYLIST_RUNTIME_UNKNOWN;
PLAYLIST_SET_RUNTIME_STATUS(&playlist->entries[0],
PLAYLIST_RUNTIME_UNKNOWN);
PLAYLIST_SET_RUNTIME_HOURS(&playlist->entries[0], 0);
PLAYLIST_SET_RUNTIME_MINUTES(&playlist->entries[0], 0);
PLAYLIST_SET_RUNTIME_SECONDS(&playlist->entries[0], 0);
@@ -1750,7 +1753,8 @@ static bool playlist_push_new_entry(playlist_t *playlist,
playlist->entries[0].path = strdup(path_id->real_path);
playlist->entries[0].path_id = path_id;
playlist->entries[0].entry_slot = entry->entry_slot;
PLAYLIST_SET_ENTRY_SLOT(&playlist->entries[0],
PLAYLIST_ENTRY_SLOT(entry));
if (entry->label && *entry->label)
playlist->entries[0].label = strdup(entry->label);
@@ -1898,10 +1902,11 @@ bool playlist_push(playlist_t *playlist,
}
/* Only write non-redundant entry slot numbers */
if ( playlist->entries[i].entry_slot != entry->entry_slot
&& (int)entry->entry_slot > 0)
if ( PLAYLIST_ENTRY_SLOT(&playlist->entries[i]) != PLAYLIST_ENTRY_SLOT(entry)
&& (int)PLAYLIST_ENTRY_SLOT(entry) > 0)
{
playlist->entries[i].entry_slot = entry->entry_slot;
PLAYLIST_SET_ENTRY_SLOT(&playlist->entries[i],
PLAYLIST_ENTRY_SLOT(entry));
entry_updated = true;
}
@@ -2482,7 +2487,7 @@ void playlist_write_file(playlist_t *playlist)
/* Typecast required because playlist_entry.entry_slot is unsigned,
* and 0 and -1 are redundant, but runloop.entry_state_slot is int16_t
* and must be able to be negative, because 0 is a valid slot */
if ( (int)playlist->entries[i].entry_slot > 0
if ( (int)PLAYLIST_ENTRY_SLOT(&playlist->entries[i]) > 0
&& !strstr(playlist->config.path, FILE_PATH_BUILTIN))
{
rjsonwriter_raw(writer, ",", 1);
@@ -2490,7 +2495,8 @@ void playlist_write_file(playlist_t *playlist)
rjsonwriter_add_spaces(writer, 6);
rjsonwriter_add_string(writer, "entry_slot");
rjsonwriter_raw(writer, ": ", 2);
rjsonwriter_rawf(writer, "%d", (int)playlist->entries[i].entry_slot);
rjsonwriter_rawf(writer, "%d",
(int)PLAYLIST_ENTRY_SLOT(&playlist->entries[i]));
}
if (playlist->entries[i].subsystem_ident && *playlist->entries[i].subsystem_ident)
@@ -2874,6 +2880,9 @@ static bool JSONNumberHandler(void *context, const char *pValue, size_t len)
unsigned v = (unsigned)strtoul(pValue, NULL, 10);
switch (pCtx->current_entry_packed_val)
{
case PLAYLIST_JSON_PACKED_ENTRY_SLOT:
PLAYLIST_SET_ENTRY_SLOT(pCtx->current_entry, v);
break;
case PLAYLIST_JSON_PACKED_RUNTIME_HOURS:
PLAYLIST_SET_RUNTIME_HOURS(pCtx->current_entry, v);
break;
@@ -2989,7 +2998,7 @@ static bool JSONObjectMemberHandler(void *context, const char *pValue, size_t le
break;
case 'e':
if (!strcmp(pValue, "entry_slot"))
pCtx->current_entry_uint_val = &pCtx->current_entry->entry_slot;
pCtx->current_entry_packed_val = PLAYLIST_JSON_PACKED_ENTRY_SLOT;
break;
case 'l':
if (!strcmp(pValue, "label"))
+19 -3
View File
@@ -130,7 +130,6 @@ struct playlist_entry
char *last_played_str;
struct string_list *subsystem_roms;
playlist_path_id_t *path_id;
unsigned entry_slot;
/* Note: due to platform dependence, have to record
* timestamp as either a string or independent integer
* values. The latter is more verbose, but more efficient.
@@ -145,10 +144,27 @@ struct playlist_entry
uint32_t runtime; /* hours:20 | minutes:6 | seconds:6 */
uint32_t last_played_ymd; /* year:16 | month:4 | day:5 */
uint32_t last_played_hms; /* hour:5 | minute:6 | second:6 */
enum playlist_runtime_status runtime_status;
int thumbnail_flags;
/* Packed, for the same reason as the timestamps above: the slot
* index is a subsystem content slot, the runtime status has three
* values and the thumbnail flags are five bits. */
uint32_t attr; /* slot:16 | status:3 | thumbs:5 */
};
#define PLAYLIST_ENTRY_SLOT(e) ((e)->attr & 0xffffu)
#define PLAYLIST_RUNTIME_STATUS(e) \
((enum playlist_runtime_status)(((e)->attr >> 16) & 0x7u))
#define PLAYLIST_THUMBNAIL_FLAGS(e) ((int)(((e)->attr >> 19) & 0x1fu))
#define PLAYLIST_SET_ENTRY_SLOT(e, v) \
((e)->attr = ((e)->attr & ~0xffffu) | ((uint32_t)(v) & 0xffffu))
#define PLAYLIST_SET_RUNTIME_STATUS(e, v) \
((e)->attr = ((e)->attr & ~(0x7u << 16)) \
| (((uint32_t)(v) & 0x7u) << 16))
#define PLAYLIST_SET_THUMBNAIL_FLAGS(e, v) \
((e)->attr = ((e)->attr & ~(0x1fu << 19)) \
| (((uint32_t)(v) & 0x1fu) << 19))
#define PLAYLIST_OR_THUMBNAIL_FLAGS(e, v) \
PLAYLIST_SET_THUMBNAIL_FLAGS((e), PLAYLIST_THUMBNAIL_FLAGS(e) | (int)(v))
#define PLAYLIST_RUNTIME_HOURS(e) ((e)->runtime >> 12)
#define PLAYLIST_RUNTIME_MINUTES(e) (((e)->runtime >> 6) & 0x3fu)
#define PLAYLIST_RUNTIME_SECONDS(e) ((e)->runtime & 0x3fu)
+2 -2
View File
@@ -4801,8 +4801,8 @@ static bool event_init_content(
if (menu_st && menu_st->driver_data)
playlist_get_index(playlist, menu_st->driver_data->rpl_entry_selection_ptr, &entry);
if (entry && entry->entry_slot > 0)
runloop_st->entry_state_slot = entry->entry_slot;
if (entry && PLAYLIST_ENTRY_SLOT(entry) > 0)
runloop_st->entry_state_slot = PLAYLIST_ENTRY_SLOT(entry);
entry_state_load = runloop_st->entry_state_slot > -1;
+4 -4
View File
@@ -1362,7 +1362,7 @@ void runtime_update_playlist(
/* Set fallback playlist 'runtime_status'
* (saves 'if' checks later...) */
update_entry.runtime_status = PLAYLIST_RUNTIME_MISSING;
PLAYLIST_SET_RUNTIME_STATUS(&update_entry, PLAYLIST_RUNTIME_MISSING);
/* 'Attach' runtime/last played strings */
runtime_str[0] = '\0';
@@ -1423,7 +1423,7 @@ void runtime_update_playlist(
timedate_style, date_separator);
/* Playlist entry now contains valid runtime data */
update_entry.runtime_status = PLAYLIST_RUNTIME_VALID;
PLAYLIST_SET_RUNTIME_STATUS(&update_entry, PLAYLIST_RUNTIME_VALID);
}
/* Clean up */
@@ -1433,7 +1433,7 @@ void runtime_update_playlist(
#if defined(HAVE_MENU) && (defined(HAVE_OZONE) || defined(HAVE_MATERIALUI))
/* Ozone and GLUI require runtime/last played strings
* to be populated even when no runtime is recorded */
if (update_entry.runtime_status != PLAYLIST_RUNTIME_VALID)
if (PLAYLIST_RUNTIME_STATUS(&update_entry) != PLAYLIST_RUNTIME_VALID)
{
const char *menu_ident = menu_driver_ident();
if ( !strcmp(menu_ident, "ozone")
@@ -1447,7 +1447,7 @@ void runtime_update_playlist(
/* While runtime data does not exist, the playlist
* entry does now contain valid information... */
update_entry.runtime_status = PLAYLIST_RUNTIME_VALID;
PLAYLIST_SET_RUNTIME_STATUS(&update_entry, PLAYLIST_RUNTIME_VALID);
}
}
#endif
+3 -3
View File
@@ -2199,7 +2199,7 @@ static void task_push_to_history_list(
entry.subsystem_ident = (char*)path_get(RARCH_PATH_SUBSYSTEM);
entry.subsystem_name = (char*)subsystem_name;
entry.subsystem_roms = (struct string_list*)path_get_subsystem_list();
entry.entry_slot = runloop_st->entry_state_slot;
PLAYLIST_SET_ENTRY_SLOT(&entry, runloop_st->entry_state_slot);
command_playlist_push_write(playlist_hist, &entry);
#if TARGET_OS_TV
@@ -2295,7 +2295,7 @@ static bool task_push_to_history_list_from_playlist_pre_load_static(
{
label = pl_entry->label;
crc32 = pl_entry->crc32;
ss_entry_slot = pl_entry->entry_slot;
ss_entry_slot = PLAYLIST_ENTRY_SLOT(pl_entry);
}
playlist_get_db_name(playlist_curr,
@@ -2323,7 +2323,7 @@ static bool task_push_to_history_list_from_playlist_pre_load_static(
new_entry.core_name = (char*)core_name;
new_entry.crc32 = (char*)crc32;
new_entry.db_name = (char*)db_name;
new_entry.entry_slot = ss_entry_slot;
PLAYLIST_SET_ENTRY_SLOT(&new_entry, ss_entry_slot);
/* TODO/FIXME: Subsystems are not properly supported
* on static platforms, so exclude the following:
+1 -1
View File
@@ -2209,7 +2209,7 @@ static bool manual_scan_end_flush_tick(
entry.subsystem_ident = NULL;
entry.subsystem_name = NULL;
entry.subsystem_roms = NULL;
entry.entry_slot = 0;
PLAYLIST_SET_ENTRY_SLOT(&entry, 0);
PLAYLIST_SET_RUNTIME_HOURS(&entry, 0);
PLAYLIST_SET_RUNTIME_MINUTES(&entry, 0);
PLAYLIST_SET_RUNTIME_SECONDS(&entry, 0);