1 #ifndef __GTK_ISTRING_PRIVATE_H__
2 #define __GTK_ISTRING_PRIVATE_H__
3 
4 #include <glib.h>
5 #include <string.h>
6 
7 typedef struct
8 {
9   guint n_bytes;
10   guint n_chars;
11   union {
12     char  buf[24];
13     char *str;
14   } u;
15 } IString;
16 
17 static inline gboolean
istring_is_inline(const IString * str)18 istring_is_inline (const IString *str)
19 {
20   return str->n_bytes <= (sizeof str->u.buf - 1);
21 }
22 
23 static inline char *
istring_str(IString * str)24 istring_str (IString *str)
25 {
26   if (istring_is_inline (str))
27     return str->u.buf;
28   else
29     return str->u.str;
30 }
31 
32 static inline void
istring_clear(IString * str)33 istring_clear (IString *str)
34 {
35   if (istring_is_inline (str))
36     str->u.buf[0] = 0;
37   else
38     g_clear_pointer (&str->u.str, g_free);
39 
40   str->n_bytes = 0;
41   str->n_chars = 0;
42 }
43 
44 static inline void
istring_set(IString * str,const char * text,guint n_bytes,guint n_chars)45 istring_set (IString    *str,
46              const char *text,
47              guint       n_bytes,
48              guint       n_chars)
49 {
50   if G_LIKELY (n_bytes <= (sizeof str->u.buf - 1))
51     {
52       memcpy (str->u.buf, text, n_bytes);
53       str->u.buf[n_bytes] = 0;
54     }
55   else
56     {
57       str->u.str = g_strndup (text, n_bytes);
58     }
59 
60   str->n_bytes = n_bytes;
61   str->n_chars = n_chars;
62 }
63 
64 static inline gboolean
istring_empty(IString * str)65 istring_empty (IString *str)
66 {
67   return str->n_bytes == 0;
68 }
69 
70 static inline gboolean
istring_ends_with_space(IString * str)71 istring_ends_with_space (IString *str)
72 {
73   return g_ascii_isspace (istring_str (str)[str->n_bytes - 1]);
74 }
75 
76 static inline gboolean
istring_starts_with_space(IString * str)77 istring_starts_with_space (IString *str)
78 {
79   return g_unichar_isspace (g_utf8_get_char (istring_str (str)));
80 }
81 
82 static inline gboolean
istring_contains_unichar(IString * str,gunichar ch)83 istring_contains_unichar (IString  *str,
84                           gunichar  ch)
85 {
86   return g_utf8_strchr (istring_str (str), str->n_bytes, ch) != NULL;
87 }
88 
89 static inline gboolean
istring_only_contains_space(IString * str)90 istring_only_contains_space (IString *str)
91 {
92   const char *iter;
93 
94   for (iter = istring_str (str); *iter; iter = g_utf8_next_char (iter))
95     {
96       if (!g_unichar_isspace (g_utf8_get_char (iter)))
97         return FALSE;
98     }
99 
100   return TRUE;
101 }
102 
103 static inline gboolean
istring_contains_space(IString * str)104 istring_contains_space (IString *str)
105 {
106   const char *iter;
107 
108   for (iter = istring_str (str); *iter; iter = g_utf8_next_char (iter))
109     {
110       if (g_unichar_isspace (g_utf8_get_char (iter)))
111         return TRUE;
112     }
113 
114   return FALSE;
115 }
116 
117 static inline void
istring_prepend(IString * str,IString * other)118 istring_prepend (IString *str,
119                  IString *other)
120 {
121   if G_LIKELY (str->n_bytes + other->n_bytes < sizeof str->u.buf - 1)
122     {
123       memmove (str->u.buf + other->n_bytes, str->u.buf, str->n_bytes);
124       memcpy (str->u.buf, other->u.buf, other->n_bytes);
125       str->n_bytes += other->n_bytes;
126       str->n_chars += other->n_chars;
127       str->u.buf[str->n_bytes] = 0;
128     }
129   else
130     {
131       char *old = NULL;
132 
133       if (!istring_is_inline (str))
134         old = str->u.str;
135 
136       str->u.str = g_strconcat (istring_str (str), istring_str (other), NULL);
137       str->n_bytes += other->n_bytes;
138       str->n_chars += other->n_chars;
139 
140       g_free (old);
141     }
142 }
143 
144 static inline void
istring_append(IString * str,IString * other)145 istring_append (IString *str,
146                 IString *other)
147 {
148   const char *text = istring_str (other);
149   guint n_bytes = other->n_bytes;
150   guint n_chars = other->n_chars;
151 
152   if G_LIKELY (istring_is_inline (str))
153     {
154       if G_LIKELY (str->n_bytes + n_bytes <= (sizeof str->u.buf - 1))
155         memcpy (str->u.buf + str->n_bytes, text, n_bytes);
156       else
157         str->u.str = g_strconcat (str->u.buf, text, NULL);
158     }
159   else
160     {
161       str->u.str = g_realloc (str->u.str, str->n_bytes + n_bytes + 1);
162       memcpy (str->u.str + str->n_bytes, text, n_bytes);
163     }
164 
165   str->n_bytes += n_bytes;
166   str->n_chars += n_chars;
167 
168   istring_str (str)[str->n_bytes] = 0;
169 }
170 
171 #endif /* __GTK_ISTRING_PRIVATE_H__ */
172