@@ -97,18 +97,30 @@ typedef union sz_string_t {
9797
9898/*
9999 * 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.
100+ * On little-endian 64-bit: internal.length (8-bit) overlaps with LSB of external.length at offset 8.
101+ * On little-endian 32-bit: internal.length (8-bit) overlaps with LSB of external.length at offset 4.
102+ * On big-endian 64-bit: internal.length is at offset 31, external.length at offset 24.
103+ * On big-endian 32-bit: internal.length is at offset 15, external.length at offset 12.
102104 */
103105#if !SZ_AVOID_LIBC // `offsetof` comes from `stddef.h`, which is part of the C standard library.
104106sz_static_assert (offsetof (sz_string_t , internal .start ) == offsetof(sz_string_t , external .start ),
105107 Alignment_confusion_between_internal_and_external_storage );
106108#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+ #if SZ_IS_64BIT_
110+ sz_static_assert (offsetof (sz_string_t , internal .length ) == 8 , Internal_length_offset_mismatch_on_little_endian_64 );
111+ sz_static_assert (offsetof (sz_string_t , external .length ) == 8 , External_length_offset_mismatch_on_little_endian_64 );
109112#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 );
113+ sz_static_assert (offsetof (sz_string_t , internal .length ) == 4 , Internal_length_offset_mismatch_on_little_endian_32 );
114+ sz_static_assert (offsetof (sz_string_t , external .length ) == 4 , External_length_offset_mismatch_on_little_endian_32 );
115+ #endif
116+ #else // SZ_IS_BIG_ENDIAN_
117+ #if SZ_IS_64BIT_
118+ sz_static_assert (offsetof (sz_string_t , internal .length ) == 31 , Internal_length_offset_mismatch_on_big_endian_64 );
119+ sz_static_assert (offsetof (sz_string_t , external .length ) == 24 , External_length_offset_mismatch_on_big_endian_64 );
120+ #else
121+ sz_static_assert (offsetof (sz_string_t , internal .length ) == 15 , Internal_length_offset_mismatch_on_big_endian_32 );
122+ sz_static_assert (offsetof (sz_string_t , external .length ) == 12 , External_length_offset_mismatch_on_big_endian_32 );
123+ #endif
112124#endif
113125#endif
114126
@@ -231,26 +243,26 @@ SZ_PUBLIC sz_bool_t sz_string_is_on_stack(sz_string_t const *string) {
231243
232244SZ_PUBLIC void sz_string_range (sz_string_t const * string , sz_ptr_t * start , sz_size_t * length ) {
233245 sz_size_t is_small = (sz_cptr_t )string -> internal .start == (sz_cptr_t )& string -> internal .chars [0 ];
234- sz_size_t is_big_mask = is_small - 1ull ;
246+ sz_size_t is_big_mask = is_small - ( sz_size_t ) 1 ;
235247 * start = string -> external .start ; // It doesn't matter if it's on stack or heap, the pointer location is the same.
236- // If the string is small, use branch-less approach to mask-out the top 7 bytes of the length.
237- * length = string -> external .length & (0x00000000000000FFull | is_big_mask );
248+ // If the string is small, use branch-less approach to mask-out the top bytes of the length.
249+ * length = string -> external .length & (( sz_size_t ) 0xFF | is_big_mask );
238250}
239251
240252SZ_PUBLIC sz_size_t sz_string_length (sz_string_t const * string ) {
241253 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 string -> external .length & (0x00000000000000FFull | is_big_mask );
254+ sz_size_t is_big_mask = is_small - ( sz_size_t ) 1 ;
255+ return string -> external .length & (( sz_size_t ) 0xFF | is_big_mask );
244256}
245257
246258SZ_PUBLIC void sz_string_unpack ( //
247259 sz_string_t const * string , sz_ptr_t * start , sz_size_t * length , sz_size_t * space , sz_bool_t * is_external ) {
248260 sz_size_t is_small = (sz_cptr_t )string -> internal .start == (sz_cptr_t )& string -> internal .chars [0 ];
249- sz_size_t is_big_mask = is_small - 1ull ;
261+ sz_size_t is_big_mask = is_small - ( sz_size_t ) 1 ;
250262 * start = string -> external .start ; // It doesn't matter if it's on stack or heap, the pointer location is the same.
251- // If the string is small, use branch-less approach to mask-out the top 7 bytes of the length.
252- * length = string -> external .length & (0x00000000000000FFull | is_big_mask );
253- // In case the string is small, the `is_small - 1ull ` will become 0xFFFFFFFFFFFFFFFFull .
263+ // If the string is small, use branch-less approach to mask-out the top bytes of the length.
264+ * length = string -> external .length & (( sz_size_t ) 0xFF | is_big_mask );
265+ // In case the string is small, the `is_small - (sz_size_t)1 ` will become all-ones mask .
254266 * space = sz_u64_blend (SZ_STRING_INTERNAL_SPACE , string -> external .space , is_big_mask );
255267 * is_external = (sz_bool_t )!is_small ;
256268}
@@ -408,7 +420,7 @@ SZ_PUBLIC sz_ptr_t sz_string_expand( //
408420 }
409421 // If we are not lucky, we need to allocate more memory.
410422 else {
411- sz_size_t next_planned_size = sz_max_of_two (SZ_CACHE_LINE_WIDTH , string_space * 2ull );
423+ sz_size_t next_planned_size = sz_max_of_two (SZ_CACHE_LINE_WIDTH , string_space * ( sz_size_t ) 2 );
412424 sz_size_t min_needed_space = sz_size_bit_ceil (offset + string_length + added_length + 1 );
413425 sz_size_t new_space = sz_max_of_two (min_needed_space , next_planned_size );
414426 string_start = sz_string_reserve (string , new_space - 1 , allocator );
0 commit comments