summaryrefslogtreecommitdiff
path: root/src/lib/eina
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2017-01-11 15:34:15 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-01-17 14:20:55 +0900
commit4550b4cf832b256d6bca49a5e536c2327bbd5e8c (patch)
treefc8a78df24a6b3e108bd80609e13836c9fd106e1 /src/lib/eina
parent4f5e64fdea88ba7362d77a6d42ea22cf13d3323f (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/lib/eina')
-rw-r--r--src/lib/eina/Eina.h1
-rw-r--r--src/lib/eina/eina_freeq.h3
-rw-r--r--src/lib/eina/eina_main.c3
-rw-r--r--src/lib/eina/eina_slstr.c215
-rw-r--r--src/lib/eina/eina_slstr.h179
5 files changed, 400 insertions, 1 deletions
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
158struct eina_desc_setup 160struct 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};
203static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / 206static 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
16static int _slstr_init = 0;
17static Eina_FreeQ *_slstr_main_fq = NULL;
18static Eina_TLS _slstr_tls = 0;
19
20// ========================================================================= //
21
22#if 0
23// 2 extension ideas here: slices for short-lived raw data buffers
24EAPI Eina_Rw_Slice eina_slslice_new(size_t length); // alloc
25EAPI Eina_Rw_Slice eina_slslice_copy(Eina_Slice slice); // copies
26EAPI Eina_Rw_Slice eina_slslice_free(Eina_Rw_Slice slice); // steals
27#endif
28
29static void
30_slstr_tls_free_cb(void *ptr)
31{
32 Eina_FreeQ *fq = ptr;
33
34 eina_freeq_free(fq);
35}
36
37Eina_Bool
38eina_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
48fail_tls:
49 eina_tls_free(_slstr_tls);
50 _slstr_tls = 0;
51fail:
52 eina_freeq_free(_slstr_main_fq);
53 _slstr_main_fq = NULL;
54 return EINA_FALSE;
55}
56
57Eina_Bool
58eina_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
71static 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
90EAPI Eina_Slstr *
91eina_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
111EAPI Eina_Slstr *
112eina_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
129EAPI Eina_Slstr *
130eina_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
147EAPI Eina_Slstr *
148eina_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
165EAPI Eina_Slstr *
166eina_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
185EAPI Eina_Slstr *
186eina_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
206EAPI void
207eina_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
34typedef 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 */
51EAPI Eina_Slstr *
52eina_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 */
68EAPI Eina_Slstr *
69eina_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 */
85EAPI Eina_Slstr *
86eina_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 */
102EAPI Eina_Slstr *
103eina_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 */
123EAPI Eina_Slstr *
124eina_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 */
135EAPI Eina_Slstr *
136eina_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 */
152static inline Eina_Slstr *
153eina_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 */
175EAPI void
176eina_slstr_local_clear(void);
177#endif
178
179#endif