forked from AuroraMiddleware/gtk
5e341210a1
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.
172 lines
3.5 KiB
C
172 lines
3.5 KiB
C
#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__ */
|