#pragma once #include #include typedef struct { guint n_bytes; guint n_chars; union { char buf[24]; char *str; } u; } IString; static inline gboolean istring_is_inline (const IString *str) { return str->n_bytes <= (sizeof str->u.buf - 1); } static inline char * istring_str (IString *str) { if (istring_is_inline (str)) return str->u.buf; else return str->u.str; } static inline void istring_clear (IString *str) { if (istring_is_inline (str)) str->u.buf[0] = 0; else g_clear_pointer (&str->u.str, g_free); str->n_bytes = 0; str->n_chars = 0; } static inline void istring_set (IString *str, const char *text, guint n_bytes, guint n_chars) { if G_LIKELY (n_bytes <= (sizeof str->u.buf - 1)) { memcpy (str->u.buf, text, n_bytes); str->u.buf[n_bytes] = 0; } else { str->u.str = g_strndup (text, n_bytes); } str->n_bytes = n_bytes; str->n_chars = n_chars; } static inline gboolean istring_empty (IString *str) { return str->n_bytes == 0; } static inline gboolean istring_ends_with_space (IString *str) { return g_ascii_isspace (istring_str (str)[str->n_bytes - 1]); } static inline gboolean istring_starts_with_space (IString *str) { return g_unichar_isspace (g_utf8_get_char (istring_str (str))); } static inline gboolean istring_contains_unichar (IString *str, gunichar ch) { return g_utf8_strchr (istring_str (str), str->n_bytes, ch) != NULL; } static inline gboolean istring_only_contains_space (IString *str) { const char *iter; for (iter = istring_str (str); *iter; iter = g_utf8_next_char (iter)) { if (!g_unichar_isspace (g_utf8_get_char (iter))) return FALSE; } return TRUE; } static inline gboolean istring_contains_space (IString *str) { const char *iter; for (iter = istring_str (str); *iter; iter = g_utf8_next_char (iter)) { if (g_unichar_isspace (g_utf8_get_char (iter))) return TRUE; } return FALSE; } static inline void istring_prepend (IString *str, IString *other) { if G_LIKELY (str->n_bytes + other->n_bytes < sizeof str->u.buf - 1) { memmove (str->u.buf + other->n_bytes, str->u.buf, str->n_bytes); memcpy (str->u.buf, other->u.buf, other->n_bytes); str->n_bytes += other->n_bytes; str->n_chars += other->n_chars; str->u.buf[str->n_bytes] = 0; } else { char *old = NULL; if (!istring_is_inline (str)) old = str->u.str; str->u.str = g_strconcat (istring_str (other), istring_str (str), NULL); str->n_bytes += other->n_bytes; str->n_chars += other->n_chars; g_free (old); } } static inline void istring_append (IString *str, IString *other) { const char *text = istring_str (other); guint n_bytes = other->n_bytes; guint n_chars = other->n_chars; if G_LIKELY (istring_is_inline (str)) { if G_LIKELY (str->n_bytes + n_bytes <= (sizeof str->u.buf - 1)) memcpy (str->u.buf + str->n_bytes, text, n_bytes); else str->u.str = g_strconcat (str->u.buf, text, NULL); } else { str->u.str = g_realloc (str->u.str, str->n_bytes + n_bytes + 1); memcpy (str->u.str + str->n_bytes, text, n_bytes); } str->n_bytes += n_bytes; str->n_chars += n_chars; istring_str (str)[str->n_bytes] = 0; }