summaryrefslogtreecommitdiff
path: root/gtk/gtkistringprivate.h
diff options
context:
space:
mode:
authorChristian Hergert <chergert@redhat.com>2019-10-23 19:13:11 -0700
committerChristian Hergert <chergert@redhat.com>2019-11-05 09:34:29 -0800
commit5e341210a1cfa08a34cb257039416a97a0ab4929 (patch)
tree6d5777a28391bc0744640bd10f0efa0f1dc096c3 /gtk/gtkistringprivate.h
parentfbea677a5c6948684317f872bc6740f3c03e4b3b (diff)
downloadgtk+-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.h171
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__ */