diff options
author | Christian Hergert <chergert@redhat.com> | 2019-10-23 19:13:11 -0700 |
---|---|---|
committer | Christian Hergert <chergert@redhat.com> | 2019-11-05 09:34:29 -0800 |
commit | 5e341210a1cfa08a34cb257039416a97a0ab4929 (patch) | |
tree | 6d5777a28391bc0744640bd10f0efa0f1dc096c3 /gtk/gtkistringprivate.h | |
parent | fbea677a5c6948684317f872bc6740f3c03e4b3b (diff) | |
download | gtk+-5e341210a1cfa08a34cb257039416a97a0ab4929.tar.gz |
texthistory: add GtkTextHistory helper
The GtkTextHistory helper provides the fundamental undo/redo stack that
can be integrated with other text widgets. It allows coalescing related
actions to reduce both the number of undo actions to the user as well as
the memory overhead.
A new istring helper is used by GtkTextHistory to allow for "inline
strings" that gracefully grow to using allocations with g_realloc(). This
ensure that most undo operations require no additional allocations other
than the struct for the action itself.
A queue of undoable and redoable actions are maintained and the link for
the queue is embedded in the undo action union. This allows again, for
reducing the number of allocations involved for undo operations.
Diffstat (limited to 'gtk/gtkistringprivate.h')
-rw-r--r-- | gtk/gtkistringprivate.h | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/gtk/gtkistringprivate.h b/gtk/gtkistringprivate.h new file mode 100644 index 0000000000..0af8cb1593 --- /dev/null +++ b/gtk/gtkistringprivate.h @@ -0,0 +1,171 @@ +#ifndef __GTK_ISTRING_PRIVATE_H__ +#define __GTK_ISTRING_PRIVATE_H__ + +#include <glib.h> +#include <string.h> + +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 + { + gchar *old = NULL; + + if (!istring_is_inline (str)) + old = str->u.str; + + str->u.str = g_strconcat (istring_str (str), istring_str (other), 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 gchar *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; +} + +#endif /* __GTK_ISTRING_PRIVATE_H__ */ |