@@ -95,9 +95,21 @@ typedef union sz_string_t {
9595
9696} sz_string_t ;
9797
98+ /*
99+ * Verify structure layout for branchless length extraction.
100+ * On little-endian: internal.length (8-bit) overlaps with LSB of external.length at offset 8.
101+ * On big-endian: internal.length is at offset 31, external.length at offset 24.
102+ */
98103#if !SZ_AVOID_LIBC // `offsetof` comes from `stddef.h`, which is part of the C standard library.
99104sz_static_assert (offsetof (sz_string_t , internal .start ) == offsetof(sz_string_t , external .start ),
100105 Alignment_confusion_between_internal_and_external_storage );
106+ #if !SZ_IS_BIG_ENDIAN_
107+ sz_static_assert (offsetof (sz_string_t , internal .length ) == 8 , Internal_length_offset_mismatch_on_little_endian );
108+ sz_static_assert (offsetof (sz_string_t , external .length ) == 8 , External_length_offset_mismatch_on_little_endian );
109+ #else
110+ sz_static_assert (offsetof (sz_string_t , internal .length ) == 31 , Internal_length_offset_mismatch_on_big_endian );
111+ sz_static_assert (offsetof (sz_string_t , external .length ) == 24 , External_length_offset_mismatch_on_big_endian );
112+ #endif
101113#endif
102114
103115#pragma endregion // Core Structure
@@ -138,6 +150,11 @@ SZ_PUBLIC void sz_string_unpack( //
138150 */
139151SZ_PUBLIC void sz_string_range (sz_string_t const * string , sz_ptr_t * start , sz_size_t * length );
140152
153+ /**
154+ * @brief Branchless check if the string is empty.
155+ */
156+ SZ_PUBLIC sz_bool_t sz_string_is_empty (sz_string_t const * string );
157+
141158/**
142159 * @brief Constructs a string of a given ::length with noisy contents.
143160 * Use the returned character pointer to populate the string.
@@ -220,6 +237,12 @@ SZ_PUBLIC void sz_string_range(sz_string_t const *string, sz_ptr_t *start, sz_si
220237 * length = string -> external .length & (0x00000000000000FFull | is_big_mask );
221238}
222239
240+ SZ_PUBLIC sz_bool_t sz_string_is_empty (sz_string_t const * string ) {
241+ sz_size_t is_small = (sz_cptr_t )string -> internal .start == (sz_cptr_t )& string -> internal .chars [0 ];
242+ sz_size_t is_big_mask = is_small - 1ull ;
243+ return (sz_bool_t )((string -> external .length & (0x00000000000000FFull | is_big_mask )) == 0 );
244+ }
245+
223246SZ_PUBLIC void sz_string_unpack ( //
224247 sz_string_t const * string , sz_ptr_t * start , sz_size_t * length , sz_size_t * space , sz_bool_t * is_external ) {
225248 sz_size_t is_small = (sz_cptr_t )string -> internal .start == (sz_cptr_t )& string -> internal .chars [0 ];
0 commit comments