diff options
author | Jean-Philippe Andre <jp.andre@samsung.com> | 2017-01-11 15:34:15 +0900 |
---|---|---|
committer | Jean-Philippe Andre <jp.andre@samsung.com> | 2017-01-17 14:20:55 +0900 |
commit | 4550b4cf832b256d6bca49a5e536c2327bbd5e8c (patch) | |
tree | fc8a78df24a6b3e108bd80609e13836c9fd106e1 /src | |
parent | 4f5e64fdea88ba7362d77a6d42ea22cf13d3323f (diff) |
eina: Introduce Eina_Slstr for short-lived strings
Built on top of the new 'postponed' free queue, the short-lived
strings API allows users to return new strings without caring
about freeing them. EFL main loop will do this automatically for
them you at a later point in time (at the end of an iteration).
The APIs provided will either duplicate (copy) or more generally
steal an existing string (char *, stringshare, tmpstr, strbuf),
taking ownership of it and controling its lifetime. Those strings
can then be safely returned by an API. From a user point of view,
those strings must be considered like simple const char *, ie.
no need to free() them and their validity is limited to the
local scope.
There is no function to remove such a string from the freeq.
The short lived strings API is not thread-safe: do not send a
short-lived object from one thread to another.
@feature
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile_Eina.am | 9 | ||||
-rw-r--r-- | src/lib/ecore/ecore_main.c | 7 | ||||
-rw-r--r-- | src/lib/eina/Eina.h | 1 | ||||
-rw-r--r-- | src/lib/eina/eina_freeq.h | 3 | ||||
-rw-r--r-- | src/lib/eina/eina_main.c | 3 | ||||
-rw-r--r-- | src/lib/eina/eina_slstr.c | 215 | ||||
-rw-r--r-- | src/lib/eina/eina_slstr.h | 179 | ||||
-rw-r--r-- | src/tests/eina/eina_suite.c | 1 | ||||
-rw-r--r-- | src/tests/eina/eina_suite.h | 1 | ||||
-rw-r--r-- | src/tests/eina/eina_test_slstr.c | 208 |
10 files changed, 623 insertions, 4 deletions
diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am index 56b195910f..ae3d94ba2f 100644 --- a/src/Makefile_Eina.am +++ b/src/Makefile_Eina.am | |||
@@ -103,7 +103,8 @@ lib/eina/eina_inline_safepointer.x \ | |||
103 | lib/eina/eina_slice.h \ | 103 | lib/eina/eina_slice.h \ |
104 | lib/eina/eina_inline_slice.x \ | 104 | lib/eina/eina_inline_slice.x \ |
105 | lib/eina/eina_inline_modinfo.x \ | 105 | lib/eina/eina_inline_modinfo.x \ |
106 | lib/eina/eina_freeq.h | 106 | lib/eina/eina_freeq.h \ |
107 | lib/eina/eina_slstr.h | ||
107 | 108 | ||
108 | 109 | ||
109 | lib_eina_libeina_la_SOURCES = \ | 110 | lib_eina_libeina_la_SOURCES = \ |
@@ -177,7 +178,8 @@ lib/eina/eina_strbuf_common.h \ | |||
177 | lib/eina/eina_quaternion.c \ | 178 | lib/eina/eina_quaternion.c \ |
178 | lib/eina/eina_bezier.c \ | 179 | lib/eina/eina_bezier.c \ |
179 | lib/eina/eina_safepointer.c \ | 180 | lib/eina/eina_safepointer.c \ |
180 | lib/eina/eina_freeq.c | 181 | lib/eina/eina_freeq.c \ |
182 | lib/eina/eina_slstr.c | ||
181 | 183 | ||
182 | 184 | ||
183 | if HAVE_WIN32 | 185 | if HAVE_WIN32 |
@@ -348,7 +350,8 @@ tests/eina/eina_test_vector.c \ | |||
348 | tests/eina/eina_test_bezier.c \ | 350 | tests/eina/eina_test_bezier.c \ |
349 | tests/eina/eina_test_safepointer.c \ | 351 | tests/eina/eina_test_safepointer.c \ |
350 | tests/eina/eina_test_slice.c \ | 352 | tests/eina/eina_test_slice.c \ |
351 | tests/eina/eina_test_freeq.c | 353 | tests/eina/eina_test_freeq.c \ |
354 | tests/eina/eina_test_slstr.c | ||
352 | 355 | ||
353 | tests_eina_eina_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ | 356 | tests_eina_eina_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ |
354 | -DTESTS_WD=\"`pwd`\" \ | 357 | -DTESTS_WD=\"`pwd`\" \ |
diff --git a/src/lib/ecore/ecore_main.c b/src/lib/ecore/ecore_main.c index 6bff19156f..ebd272d669 100644 --- a/src/lib/ecore/ecore_main.c +++ b/src/lib/ecore/ecore_main.c | |||
@@ -2,6 +2,8 @@ | |||
2 | # include <config.h> | 2 | # include <config.h> |
3 | #endif | 3 | #endif |
4 | 4 | ||
5 | #define EINA_SLSTR_INTERNAL | ||
6 | |||
5 | #ifdef _WIN32 | 7 | #ifdef _WIN32 |
6 | # define WIN32_LEAN_AND_MEAN | 8 | # define WIN32_LEAN_AND_MEAN |
7 | # include <winsock2.h> | 9 | # include <winsock2.h> |
@@ -2388,6 +2390,11 @@ process_all: /*-*********************************************************/ | |||
2388 | done: /*-*****************************************************************/ | 2390 | done: /*-*****************************************************************/ |
2389 | /* Agressively flush animator */ | 2391 | /* Agressively flush animator */ |
2390 | _ecore_animator_flush(); | 2392 | _ecore_animator_flush(); |
2393 | if (!once_only) | ||
2394 | { | ||
2395 | /* Free all short lived strings */ | ||
2396 | eina_slstr_local_clear(); | ||
2397 | } | ||
2391 | in_main_loop--; | 2398 | in_main_loop--; |
2392 | } | 2399 | } |
2393 | 2400 | ||
diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h index 374e4ecfc2..6a99b4fe68 100644 --- a/src/lib/eina/Eina.h +++ b/src/lib/eina/Eina.h | |||
@@ -271,6 +271,7 @@ extern "C" { | |||
271 | #include <eina_safepointer.h> | 271 | #include <eina_safepointer.h> |
272 | #include <eina_slice.h> | 272 | #include <eina_slice.h> |
273 | #include <eina_freeq.h> | 273 | #include <eina_freeq.h> |
274 | #include <eina_slstr.h> | ||
274 | 275 | ||
275 | #undef EAPI | 276 | #undef EAPI |
276 | #define EAPI | 277 | #define EAPI |
diff --git a/src/lib/eina/eina_freeq.h b/src/lib/eina/eina_freeq.h index 643aa1e5ce..7b34669452 100644 --- a/src/lib/eina/eina_freeq.h +++ b/src/lib/eina/eina_freeq.h | |||
@@ -89,7 +89,8 @@ typedef enum _Eina_FreeQ_Type | |||
89 | * immediately. Use this kind of freeq for debugging and additional memory | 89 | * immediately. Use this kind of freeq for debugging and additional memory |
90 | * safety purposes only. | 90 | * safety purposes only. |
91 | * | 91 | * |
92 | * This type of free queue is thread-safe. | 92 | * As this type of free queue is thread-safe, the free functions used must |
93 | * also be thread-safe (eg. libc free()). | ||
93 | * | 94 | * |
94 | * @since 1.19 | 95 | * @since 1.19 |
95 | */ | 96 | */ |
diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c index ab0aec90b1..c0e2825151 100644 --- a/src/lib/eina/eina_main.c +++ b/src/lib/eina/eina_main.c | |||
@@ -69,6 +69,7 @@ | |||
69 | #include "eina_value.h" | 69 | #include "eina_value.h" |
70 | #include "eina_evlog.h" | 70 | #include "eina_evlog.h" |
71 | #include "eina_freeq.h" | 71 | #include "eina_freeq.h" |
72 | #include "eina_slstr.h" | ||
72 | 73 | ||
73 | /*============================================================================* | 74 | /*============================================================================* |
74 | * Local * | 75 | * Local * |
@@ -153,6 +154,7 @@ EAPI Eina_Inlist *_eina_tracking = NULL; | |||
153 | S(rbtree); | 154 | S(rbtree); |
154 | S(file); | 155 | S(file); |
155 | S(safepointer); | 156 | S(safepointer); |
157 | S(slstr); | ||
156 | #undef S | 158 | #undef S |
157 | 159 | ||
158 | struct eina_desc_setup | 160 | struct eina_desc_setup |
@@ -198,6 +200,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = { | |||
198 | S(rbtree), | 200 | S(rbtree), |
199 | S(file), | 201 | S(file), |
200 | S(safepointer), | 202 | S(safepointer), |
203 | S(slstr), | ||
201 | #undef S | 204 | #undef S |
202 | }; | 205 | }; |
203 | static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / | 206 | static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / |
diff --git a/src/lib/eina/eina_slstr.c b/src/lib/eina/eina_slstr.c new file mode 100644 index 0000000000..5367db010f --- /dev/null +++ b/src/lib/eina/eina_slstr.c | |||
@@ -0,0 +1,215 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include "config.h" | ||
3 | #endif | ||
4 | |||
5 | #define EINA_SLSTR_INTERNAL | ||
6 | |||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <string.h> | ||
10 | |||
11 | #include "Eina.h" | ||
12 | #include "eina_private.h" | ||
13 | |||
14 | // ========================================================================= // | ||
15 | |||
16 | static int _slstr_init = 0; | ||
17 | static Eina_FreeQ *_slstr_main_fq = NULL; | ||
18 | static Eina_TLS _slstr_tls = 0; | ||
19 | |||
20 | // ========================================================================= // | ||
21 | |||
22 | #if 0 | ||
23 | // 2 extension ideas here: slices for short-lived raw data buffers | ||
24 | EAPI Eina_Rw_Slice eina_slslice_new(size_t length); // alloc | ||
25 | EAPI Eina_Rw_Slice eina_slslice_copy(Eina_Slice slice); // copies | ||
26 | EAPI Eina_Rw_Slice eina_slslice_free(Eina_Rw_Slice slice); // steals | ||
27 | #endif | ||
28 | |||
29 | static void | ||
30 | _slstr_tls_free_cb(void *ptr) | ||
31 | { | ||
32 | Eina_FreeQ *fq = ptr; | ||
33 | |||
34 | eina_freeq_free(fq); | ||
35 | } | ||
36 | |||
37 | Eina_Bool | ||
38 | eina_slstr_init(void) | ||
39 | { | ||
40 | if (_slstr_init++) return EINA_TRUE; | ||
41 | |||
42 | _slstr_main_fq = eina_freeq_new(EINA_FREEQ_POSTPONED); | ||
43 | if (!_slstr_main_fq) goto fail; | ||
44 | if (!eina_tls_cb_new(&_slstr_tls, _slstr_tls_free_cb)) goto fail_tls; | ||
45 | |||
46 | return EINA_TRUE; | ||
47 | |||
48 | fail_tls: | ||
49 | eina_tls_free(_slstr_tls); | ||
50 | _slstr_tls = 0; | ||
51 | fail: | ||
52 | eina_freeq_free(_slstr_main_fq); | ||
53 | _slstr_main_fq = NULL; | ||
54 | return EINA_FALSE; | ||
55 | } | ||
56 | |||
57 | Eina_Bool | ||
58 | eina_slstr_shutdown(void) | ||
59 | { | ||
60 | if (_slstr_init == 0) return EINA_FALSE; | ||
61 | if (--_slstr_init) return EINA_TRUE; | ||
62 | |||
63 | eina_freeq_free(_slstr_main_fq); | ||
64 | eina_tls_free(_slstr_tls); | ||
65 | _slstr_main_fq = NULL; | ||
66 | _slstr_tls = 0; | ||
67 | |||
68 | return EINA_TRUE; | ||
69 | } | ||
70 | |||
71 | static inline Eina_FreeQ * | ||
72 | _slstr_freeq_get(Eina_Bool nocreate) | ||
73 | { | ||
74 | if (eina_main_loop_is()) | ||
75 | return _slstr_main_fq; | ||
76 | else | ||
77 | { | ||
78 | Eina_FreeQ *fq; | ||
79 | |||
80 | fq = eina_tls_get(_slstr_tls); | ||
81 | if (!nocreate && EINA_UNLIKELY(!fq)) | ||
82 | { | ||
83 | fq = eina_freeq_new(EINA_FREEQ_POSTPONED); | ||
84 | eina_tls_set(_slstr_tls, fq); | ||
85 | } | ||
86 | return fq; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | EAPI Eina_Slstr * | ||
91 | eina_slstr_copy_new(const char *string) | ||
92 | { | ||
93 | Eina_FreeQ *fq; | ||
94 | char *copy; | ||
95 | size_t len = 0; | ||
96 | |||
97 | if (!string) return NULL; | ||
98 | |||
99 | fq = _slstr_freeq_get(EINA_FALSE); | ||
100 | EINA_SAFETY_ON_NULL_RETURN_VAL(fq, NULL); | ||
101 | |||
102 | copy = eina_strdup(string); | ||
103 | if (!copy) return NULL; | ||
104 | #ifdef DEBUG | ||
105 | len = strlen(string) + 1; | ||
106 | #endif | ||
107 | eina_freeq_ptr_add(fq, copy, free, len); | ||
108 | return copy; | ||
109 | } | ||
110 | |||
111 | EAPI Eina_Slstr * | ||
112 | eina_slstr_steal_new(char *string) | ||
113 | { | ||
114 | Eina_FreeQ *fq; | ||
115 | size_t len = 0; | ||
116 | |||
117 | if (!string) return NULL; | ||
118 | |||
119 | fq = _slstr_freeq_get(EINA_FALSE); | ||
120 | EINA_SAFETY_ON_NULL_RETURN_VAL(fq, NULL); | ||
121 | |||
122 | #ifdef DEBUG | ||
123 | len = strlen(string) + 1; | ||
124 | #endif | ||
125 | eina_freeq_ptr_add(fq, string, free, len); | ||
126 | return string; | ||
127 | } | ||
128 | |||
129 | EAPI Eina_Slstr * | ||
130 | eina_slstr_stringshare_new(Eina_Stringshare *string) | ||
131 | { | ||
132 | Eina_FreeQ *fq; | ||
133 | size_t len = 0; | ||
134 | |||
135 | if (!string) return NULL; | ||
136 | |||
137 | fq = _slstr_freeq_get(EINA_FALSE); | ||
138 | EINA_SAFETY_ON_NULL_RETURN_VAL(fq, NULL); | ||
139 | |||
140 | #ifdef DEBUG | ||
141 | len = eina_stringshare_strlen(string) + 1; | ||
142 | #endif | ||
143 | eina_freeq_ptr_add(fq, (void *) string, EINA_FREE_CB(eina_stringshare_del), len); | ||
144 | return string; | ||
145 | } | ||
146 | |||
147 | EAPI Eina_Slstr * | ||
148 | eina_slstr_tmpstr_new(Eina_Tmpstr *string) | ||
149 | { | ||
150 | Eina_FreeQ *fq; | ||
151 | size_t len = 0; | ||
152 | |||
153 | if (!string) return NULL; | ||
154 | |||
155 | fq = _slstr_freeq_get(EINA_FALSE); | ||
156 | EINA_SAFETY_ON_NULL_RETURN_VAL(fq, NULL); | ||
157 | |||
158 | #ifdef DEBUG | ||
159 | len = eina_tmpstr_strlen(string) + 1; | ||
160 | #endif | ||
161 | eina_freeq_ptr_add(fq, (void *) string, EINA_FREE_CB(eina_tmpstr_del), len); | ||
162 | return string; | ||
163 | } | ||
164 | |||
165 | EAPI Eina_Slstr * | ||
166 | eina_slstr_strbuf_new(Eina_Strbuf *string) | ||
167 | { | ||
168 | Eina_FreeQ *fq; | ||
169 | size_t len = 0; | ||
170 | char *str; | ||
171 | |||
172 | if (!string) return NULL; | ||
173 | |||
174 | fq = _slstr_freeq_get(EINA_FALSE); | ||
175 | EINA_SAFETY_ON_NULL_RETURN_VAL(fq, NULL); | ||
176 | |||
177 | str = eina_strbuf_release(string); | ||
178 | #ifdef DEBUG | ||
179 | len = eina_strbuf_length_get(string) + 1; | ||
180 | #endif | ||
181 | eina_freeq_ptr_add(fq, str, free, len); | ||
182 | return str; | ||
183 | } | ||
184 | |||
185 | EAPI Eina_Slstr * | ||
186 | eina_slstr_vasprintf_new(const char *fmt, va_list args) | ||
187 | { | ||
188 | Eina_FreeQ *fq; | ||
189 | size_t len = 0; | ||
190 | char *str; | ||
191 | int r; | ||
192 | |||
193 | fq = _slstr_freeq_get(EINA_FALSE); | ||
194 | EINA_SAFETY_ON_NULL_RETURN_VAL(fq, NULL); | ||
195 | |||
196 | r = vasprintf(&str, fmt, args); | ||
197 | if (r == -1) return NULL; | ||
198 | |||
199 | #ifdef DEBUG | ||
200 | len = r + 1; | ||
201 | #endif | ||
202 | eina_freeq_ptr_add(fq, str, free, len); | ||
203 | return str; | ||
204 | } | ||
205 | |||
206 | EAPI void | ||
207 | eina_slstr_local_clear(void) | ||
208 | { | ||
209 | Eina_FreeQ *fq; | ||
210 | |||
211 | fq = _slstr_freeq_get(EINA_TRUE); | ||
212 | if (!fq) return; | ||
213 | |||
214 | eina_freeq_clear(fq); | ||
215 | } | ||
diff --git a/src/lib/eina/eina_slstr.h b/src/lib/eina/eina_slstr.h new file mode 100644 index 0000000000..0e5d66e310 --- /dev/null +++ b/src/lib/eina/eina_slstr.h | |||
@@ -0,0 +1,179 @@ | |||
1 | #ifndef EINA_SLSTR_H_ | ||
2 | #define EINA_SLSTR_H_ | ||
3 | |||
4 | #include <stdlib.h> | ||
5 | |||
6 | #include "eina_config.h" | ||
7 | |||
8 | #include "eina_types.h" | ||
9 | #include "eina_tmpstr.h" | ||
10 | #include "eina_strbuf.h" | ||
11 | #include "eina_stringshare.h" | ||
12 | #include "eina_slice.h" | ||
13 | |||
14 | /** | ||
15 | * @addtogroup Eina_Slstr Short lived strings | ||
16 | * @ingroup Eina | ||
17 | * | ||
18 | * @brief API for short lived strings (thread- and scope-local) | ||
19 | * | ||
20 | * This set of APIs provide a convenience feature to create and return strings | ||
21 | * that are meant to be consumed in the local scope of the calling code block. | ||
22 | * The lifecycle of those strings is bound to the loop of the current thread | ||
23 | * or until the clear function is called explicitely. | ||
24 | * | ||
25 | * These strings will be automatically deleted. | ||
26 | * | ||
27 | * These functions shall return NULL only if out of memory. | ||
28 | * | ||
29 | * Do not call free or any similar function on a string created with this API! | ||
30 | * | ||
31 | * @since 1.19 | ||
32 | */ | ||
33 | |||
34 | typedef const char Eina_Slstr; | ||
35 | |||
36 | /** | ||
37 | * @brief Create a new short lived string by duplicating another string. | ||
38 | * | ||
39 | * @param string An existing string, it will be copied. | ||
40 | * @return A new Eina_Slstr or NULL if out of memory. | ||
41 | * | ||
42 | * Usage example: | ||
43 | * @code | ||
44 | * char local[200]; | ||
45 | * sprintf(local, "Hello %d", value); | ||
46 | * return eina_slstr_copy_new(local); | ||
47 | * @endcode | ||
48 | * | ||
49 | * @since 1.19 | ||
50 | */ | ||
51 | EAPI Eina_Slstr * | ||
52 | eina_slstr_copy_new(const char *string); | ||
53 | |||
54 | /** | ||
55 | * @brief Create a new short lived string by taking ownership of a string. | ||
56 | * | ||
57 | * @param string An existing string. It will not be duplicated. | ||
58 | * @return A new Eina_Slstr or NULL if out of memory. | ||
59 | * | ||
60 | * Usage example: | ||
61 | * @code | ||
62 | * char *local = strdup("Hello"); | ||
63 | * return eina_slstr_steal_new(local); | ||
64 | * @endcode | ||
65 | * | ||
66 | * @since 1.19 | ||
67 | */ | ||
68 | EAPI Eina_Slstr * | ||
69 | eina_slstr_steal_new(char *string); | ||
70 | |||
71 | /** | ||
72 | * @brief Create a new short lived string by taking ownership of a stringshare. | ||
73 | * | ||
74 | * @param string An existing stringshare, one reference belongs to this slstr. | ||
75 | * @return A new Eina_Slstr or NULL if out of memory. | ||
76 | * | ||
77 | * Usage example: | ||
78 | * @code | ||
79 | * Eina_Stringshare *local = eina_stringshare_add("Hello"); | ||
80 | * return eina_slstr_stringshare_new(local); | ||
81 | * @endcode | ||
82 | * | ||
83 | * @since 1.19 | ||
84 | */ | ||
85 | EAPI Eina_Slstr * | ||
86 | eina_slstr_stringshare_new(Eina_Stringshare *string); | ||
87 | |||
88 | /** | ||
89 | * @brief Create a new short lived string by taking ownership of a tmpstr. | ||
90 | * | ||
91 | * @param string An existing tmpstr, it will be freed later. | ||
92 | * @return A new Eina_Slstr or NULL if out of memory. | ||
93 | * | ||
94 | * Usage example: | ||
95 | * @code | ||
96 | * Eina_Tmpstr *local = eina_tmpstr_add("Hello"); | ||
97 | * return eina_slstr_tmpstr_new(local); | ||
98 | * @endcode | ||
99 | * | ||
100 | * @since 1.19 | ||
101 | */ | ||
102 | EAPI Eina_Slstr * | ||
103 | eina_slstr_tmpstr_new(Eina_Tmpstr *string); | ||
104 | |||
105 | /** | ||
106 | * @brief Create a new short lived string by taking ownership of a strbuf. | ||
107 | * | ||
108 | * @param string An existing strbuf, that will be released (ie. steal + free). | ||
109 | * @return A new Eina_Slstr or NULL if out of memory. | ||
110 | * | ||
111 | * Usage example: | ||
112 | * @code | ||
113 | * Eina_Strbuf *local = eina_strbuf_new(); | ||
114 | * eina_strbuf_append(local, "Hello"); | ||
115 | * eina_strbuf_append(local, " world"); | ||
116 | * return eina_slstr_strbuf_new(local); | ||
117 | * @endcode | ||
118 | * | ||
119 | * @note Use eina_slstr_steal_new() if the strbuf will be used after this call. | ||
120 | * | ||
121 | * @since 1.19 | ||
122 | */ | ||
123 | EAPI Eina_Slstr * | ||
124 | eina_slstr_strbuf_new(Eina_Strbuf *string); | ||
125 | |||
126 | /** | ||
127 | * @brief Create a new short lived string using sprintf. | ||
128 | * | ||
129 | * @param fmt Format string for printf | ||
130 | * @param args List of format parameters for printf | ||
131 | * @return A new Eina_Slstr or NULL if out of memory. | ||
132 | * | ||
133 | * @since 1.19 | ||
134 | */ | ||
135 | EAPI Eina_Slstr * | ||
136 | eina_slstr_vasprintf_new(const char *fmt, va_list args); | ||
137 | |||
138 | /** | ||
139 | * @brief Create a new short lived string using sprintf. | ||
140 | * | ||
141 | * @param fmt Format string for printf | ||
142 | * @param args List of format parameters for printf | ||
143 | * @return A new Eina_Slstr or NULL if out of memory. | ||
144 | * | ||
145 | * Usage example: | ||
146 | * @code | ||
147 | * return eina_slstr_printf("Hello world %d!", 42); | ||
148 | * @endcode | ||
149 | * | ||
150 | * @since 1.19 | ||
151 | */ | ||
152 | static inline Eina_Slstr * | ||
153 | eina_slstr_printf(const char *fmt, ...) | ||
154 | { | ||
155 | Eina_Slstr *str; | ||
156 | va_list args; | ||
157 | |||
158 | va_start(args, fmt); | ||
159 | str = eina_slstr_vasprintf_new(fmt, args); | ||
160 | va_end(args); | ||
161 | |||
162 | return str; | ||
163 | } | ||
164 | |||
165 | #ifdef EINA_SLSTR_INTERNAL | ||
166 | /** | ||
167 | * @brief Internal function to clear the strings. | ||
168 | * | ||
169 | * This internal function will be called by the local thread's loop to free | ||
170 | * all the strings. Do not call this function unless you are absolutely certain | ||
171 | * that no string in the queue will be used after this point. | ||
172 | * | ||
173 | * @since 1.19 | ||
174 | */ | ||
175 | EAPI void | ||
176 | eina_slstr_local_clear(void); | ||
177 | #endif | ||
178 | |||
179 | #endif | ||
diff --git a/src/tests/eina/eina_suite.c b/src/tests/eina/eina_suite.c index 5cb67f909e..e7e1b623d9 100644 --- a/src/tests/eina/eina_suite.c +++ b/src/tests/eina/eina_suite.c | |||
@@ -86,6 +86,7 @@ static const Efl_Test_Case etc[] = { | |||
86 | { "Slice", eina_test_slice }, | 86 | { "Slice", eina_test_slice }, |
87 | { "Free Queue", eina_test_freeq }, | 87 | { "Free Queue", eina_test_freeq }, |
88 | { "Util", eina_test_util }, | 88 | { "Util", eina_test_util }, |
89 | { "Short Lived Strings", eina_test_slstr }, | ||
89 | { NULL, NULL } | 90 | { NULL, NULL } |
90 | }; | 91 | }; |
91 | 92 | ||
diff --git a/src/tests/eina/eina_suite.h b/src/tests/eina/eina_suite.h index 6f46580aa5..7bf643e478 100644 --- a/src/tests/eina/eina_suite.h +++ b/src/tests/eina/eina_suite.h | |||
@@ -73,5 +73,6 @@ void eina_test_bezier(TCase *tc); | |||
73 | void eina_test_safepointer(TCase *tc); | 73 | void eina_test_safepointer(TCase *tc); |
74 | void eina_test_slice(TCase *tc); | 74 | void eina_test_slice(TCase *tc); |
75 | void eina_test_freeq(TCase *tc); | 75 | void eina_test_freeq(TCase *tc); |
76 | void eina_test_slstr(TCase *tc); | ||
76 | 77 | ||
77 | #endif /* EINA_SUITE_H_ */ | 78 | #endif /* EINA_SUITE_H_ */ |
diff --git a/src/tests/eina/eina_test_slstr.c b/src/tests/eina/eina_test_slstr.c new file mode 100644 index 0000000000..d7778a23bc --- /dev/null +++ b/src/tests/eina/eina_test_slstr.c | |||
@@ -0,0 +1,208 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include "config.h" | ||
3 | #endif | ||
4 | |||
5 | #define EINA_SLSTR_INTERNAL | ||
6 | #include <Eina.h> | ||
7 | |||
8 | #include "eina_suite.h" | ||
9 | |||
10 | static Eina_Slstr * | ||
11 | _slstr_copy(void) | ||
12 | { | ||
13 | const char local[] = "Hello world 1"; | ||
14 | |||
15 | return eina_slstr_copy_new(local); | ||
16 | } | ||
17 | |||
18 | START_TEST(slstr_copy) | ||
19 | { | ||
20 | Eina_Slstr *str; | ||
21 | |||
22 | eina_init(); | ||
23 | |||
24 | str = _slstr_copy(); | ||
25 | ck_assert_str_eq(str, "Hello world 1"); | ||
26 | |||
27 | eina_shutdown(); | ||
28 | } | ||
29 | END_TEST | ||
30 | |||
31 | static Eina_Slstr * | ||
32 | _slstr_steal(void) | ||
33 | { | ||
34 | char *local = strdup("Hello world 2"); | ||
35 | |||
36 | return eina_slstr_copy_new(local); | ||
37 | } | ||
38 | |||
39 | START_TEST(slstr_steal) | ||
40 | { | ||
41 | Eina_Slstr *str; | ||
42 | |||
43 | eina_init(); | ||
44 | |||
45 | str = _slstr_steal(); | ||
46 | ck_assert_str_eq(str, "Hello world 2"); | ||
47 | |||
48 | eina_shutdown(); | ||
49 | } | ||
50 | END_TEST | ||
51 | |||
52 | static Eina_Slstr * | ||
53 | _slstr_stringshare(void) | ||
54 | { | ||
55 | Eina_Stringshare *str = eina_stringshare_add("Hello world 3"); | ||
56 | |||
57 | return eina_slstr_stringshare_new(str); | ||
58 | } | ||
59 | |||
60 | START_TEST(slstr_stringshare) | ||
61 | { | ||
62 | Eina_Stringshare *ss; | ||
63 | Eina_Slstr *str; | ||
64 | |||
65 | eina_init(); | ||
66 | |||
67 | str = _slstr_stringshare(); | ||
68 | ss = eina_stringshare_add("Hello world 3"); | ||
69 | fail_if(ss != str); | ||
70 | |||
71 | eina_shutdown(); | ||
72 | } | ||
73 | END_TEST | ||
74 | |||
75 | static Eina_Slstr * | ||
76 | _slstr_tmpstr(void) | ||
77 | { | ||
78 | Eina_Tmpstr *str = eina_tmpstr_add("Hello world 4"); | ||
79 | |||
80 | return eina_slstr_tmpstr_new(str); | ||
81 | } | ||
82 | |||
83 | START_TEST(slstr_tmpstr) | ||
84 | { | ||
85 | Eina_Slstr *str; | ||
86 | |||
87 | eina_init(); | ||
88 | |||
89 | str = _slstr_tmpstr(); | ||
90 | ck_assert_str_eq(str, "Hello world 4"); | ||
91 | |||
92 | eina_shutdown(); | ||
93 | } | ||
94 | END_TEST | ||
95 | |||
96 | static Eina_Slstr * | ||
97 | _slstr_strbuf(void) | ||
98 | { | ||
99 | Eina_Strbuf *str = eina_strbuf_new(); | ||
100 | |||
101 | eina_strbuf_append(str, "Hello "); | ||
102 | eina_strbuf_append(str, "world "); | ||
103 | eina_strbuf_append_printf(str, "%d", 5); | ||
104 | |||
105 | return eina_slstr_strbuf_new(str); | ||
106 | } | ||
107 | |||
108 | START_TEST(slstr_strbuf) | ||
109 | { | ||
110 | Eina_Slstr *str; | ||
111 | |||
112 | eina_init(); | ||
113 | |||
114 | str = _slstr_strbuf(); | ||
115 | ck_assert_str_eq(str, "Hello world 5"); | ||
116 | |||
117 | eina_shutdown(); | ||
118 | } | ||
119 | END_TEST | ||
120 | |||
121 | static Eina_Slstr * | ||
122 | _slstr_printf(int val) | ||
123 | { | ||
124 | return eina_slstr_printf("Hello %s %d", "world", val); | ||
125 | } | ||
126 | |||
127 | START_TEST(slstr_slstr_printf) | ||
128 | { | ||
129 | Eina_Slstr *str; | ||
130 | |||
131 | eina_init(); | ||
132 | |||
133 | str = _slstr_printf(6); | ||
134 | ck_assert_str_eq(str, "Hello world 6"); | ||
135 | |||
136 | eina_shutdown(); | ||
137 | } | ||
138 | END_TEST | ||
139 | |||
140 | static void | ||
141 | _many_do(void) | ||
142 | { | ||
143 | const int many = 2048; | ||
144 | Eina_Slstr *str; | ||
145 | int k; | ||
146 | |||
147 | for (k = 0; k < many; k++) | ||
148 | { | ||
149 | char local[64]; | ||
150 | |||
151 | str = _slstr_printf(k); | ||
152 | sprintf(local, "Hello world %d", k); | ||
153 | ck_assert_str_eq(str, local); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | START_TEST(slstr_many) | ||
158 | { | ||
159 | eina_init(); | ||
160 | |||
161 | _many_do(); | ||
162 | |||
163 | eina_slstr_local_clear(); | ||
164 | |||
165 | eina_shutdown(); | ||
166 | } | ||
167 | END_TEST | ||
168 | |||
169 | static void * | ||
170 | _thread_cb(void *data EINA_UNUSED, Eina_Thread th EINA_UNUSED) | ||
171 | { | ||
172 | _many_do(); | ||
173 | |||
174 | return NULL; | ||
175 | } | ||
176 | |||
177 | START_TEST(slstr_thread) | ||
178 | { | ||
179 | const int threads = 8; | ||
180 | Eina_Thread th[threads]; | ||
181 | int k; | ||
182 | |||
183 | eina_init(); | ||
184 | |||
185 | for (k = 0; k < threads; k++) | ||
186 | fail_if(!eina_thread_create(&th[k], EINA_THREAD_NORMAL, -1, _thread_cb, NULL)); | ||
187 | |||
188 | for (k = 0; k < threads; k++) | ||
189 | eina_thread_join(th[k]); | ||
190 | |||
191 | eina_slstr_local_clear(); | ||
192 | |||
193 | eina_shutdown(); | ||
194 | } | ||
195 | END_TEST | ||
196 | |||
197 | void | ||
198 | eina_test_slstr(TCase *tc) | ||
199 | { | ||
200 | tcase_add_test(tc, slstr_copy); | ||
201 | tcase_add_test(tc, slstr_steal); | ||
202 | tcase_add_test(tc, slstr_stringshare); | ||
203 | tcase_add_test(tc, slstr_tmpstr); | ||
204 | tcase_add_test(tc, slstr_strbuf); | ||
205 | tcase_add_test(tc, slstr_slstr_printf); | ||
206 | tcase_add_test(tc, slstr_many); | ||
207 | tcase_add_test(tc, slstr_thread); | ||
208 | } | ||