summaryrefslogtreecommitdiff
path: root/src/lib/evas/canvas/evas_object_textblock.c
diff options
context:
space:
mode:
authorsubhransu mohanty <sub.mohanty@samsung.com>2019-08-09 17:36:35 +0900
committerHermet Park <hermetpark@gmail.com>2019-08-09 17:36:35 +0900
commit9e3a0466617dad31c611cc826fa67f66ac08dce1 (patch)
treef9d96753feeb9d1af9d559adeaec71b3e417e881 /src/lib/evas/canvas/evas_object_textblock.c
parent1b94d90d53dd71457cd92575d9f29c58d76eef75 (diff)
evas/textblock: optmize textblock format parsing.
Summary: textblock format parsing creates/delets eina_TempStr for each token. Eina_TempStr is even worse than malloc/free because it also takes a lock/unlock along with malloc/free each time we create it. Just use a stack bufefr and create string in it if the string is too big then it will fall back to heap which is anyway we are doing right now. Tested this in Tizen List view the number of allocation reduced by 16000. Reviewers: Hermet, ali.alzyod, woohyun Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9534
Diffstat (limited to 'src/lib/evas/canvas/evas_object_textblock.c')
-rw-r--r--src/lib/evas/canvas/evas_object_textblock.c115
1 files changed, 97 insertions, 18 deletions
diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c
index e069e04..4f3f4d5 100644
--- a/src/lib/evas/canvas/evas_object_textblock.c
+++ b/src/lib/evas/canvas/evas_object_textblock.c
@@ -1728,13 +1728,13 @@ _format_command_shutdown(void)
1728 * @param[in] src the source string - Should not be NULL. 1728 * @param[in] src the source string - Should not be NULL.
1729 */ 1729 */
1730static int 1730static int
1731_format_clean_param(Eina_Tmpstr *s) 1731_format_clean_param(char *s)
1732{ 1732{
1733 Eina_Tmpstr *ss; 1733 char *ss;
1734 char *ds; 1734 char *ds;
1735 int len = 0; 1735 int len = 0;
1736 1736
1737 ds = (char*) s; 1737 ds = s;
1738 for (ss = s; *ss; ss++, ds++, len++) 1738 for (ss = s; *ss; ss++, ds++, len++)
1739 { 1739 {
1740 if ((*ss == '\\') && *(ss + 1)) ss++; 1740 if ((*ss == '\\') && *(ss + 1)) ss++;
@@ -1752,10 +1752,10 @@ _format_clean_param(Eina_Tmpstr *s)
1752 * @param obj the evas object - should not be NULL. 1752 * @param obj the evas object - should not be NULL.
1753 * @param fmt The format to populate - should not be NULL. 1753 * @param fmt The format to populate - should not be NULL.
1754 * @param[in] cmd the command to process, should be stringshared. 1754 * @param[in] cmd the command to process, should be stringshared.
1755 * @param[in] param the parameter of the command. 1755 * @param[in] param the parameter of the command. may modify the string.
1756 */ 1756 */
1757static void 1757static void
1758_format_command(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const char *cmd, Eina_Tmpstr *param) 1758_format_command(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const char *cmd, char *param)
1759{ 1759{
1760 int len; 1760 int len;
1761 1761
@@ -2847,6 +2847,77 @@ _format_command(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const ch
2847 } 2847 }
2848} 2848}
2849 2849
2850/*
2851 * @internal
2852 * just to create a constant without using marco
2853 * 2 cacheline is enough for the string we parse
2854 * usually color or color_class strings.
2855 * reduce it if this number is too high.
2856 */
2857enum _Internal{ ALLOCATOR_SIZE = 120 };
2858
2859/*
2860 * @internal
2861 * A simple stack allocator which first
2862 * tries to create a string in the stack (buffer
2863 * it holds). if the string size is bigger than its
2864 * buffer capacity it will fall back to creating the
2865 * string on heap.
2866 * USAGE :
2867 * Allocator a;
2868 * _allocator_init(&a);
2869 * _allocator_make_string(&a, "hello world", 11);
2870 * ... //use the string
2871 * ._allocator_reset(&a);
2872 * Always call _allocator_reset() after
2873 * you done with the string.
2874 */
2875typedef struct _Allocator
2876{
2877 char stack[ALLOCATOR_SIZE];
2878 char *heap;
2879} Allocator;
2880
2881static inline void
2882_allocator_init(Allocator* allocator)
2883{
2884 if (allocator) allocator->heap = NULL;
2885}
2886
2887static inline void
2888_allocator_reset(Allocator* allocator)
2889{
2890 if (allocator && allocator->heap)
2891 {
2892 free(allocator->heap);
2893 allocator->heap = NULL;
2894 }
2895}
2896
2897static char *
2898_allocator_make_string(Allocator* allocator, const char* str, size_t size)
2899{
2900 if (!allocator) return NULL;
2901 if (!size) return NULL;
2902
2903 if (size + 1 < ALLOCATOR_SIZE)
2904 {
2905 memcpy(allocator->stack, str, size);
2906 allocator->stack[size] = '\0';
2907 return allocator->stack;
2908 }
2909 //fallback to heap
2910 if (allocator->heap) free(allocator->heap);
2911
2912 allocator->heap = malloc(size + 1);
2913
2914 if (!allocator->heap) return NULL;
2915
2916 memcpy(allocator->heap, str, size);
2917 allocator->heap[size] = '\0';
2918 return allocator->heap;
2919}
2920
2850/** 2921/**
2851 * @internal 2922 * @internal
2852 * Returns @c EINA_TRUE if the item is a format parameter, @c EINA_FALSE 2923 * Returns @c EINA_TRUE if the item is a format parameter, @c EINA_FALSE
@@ -2872,15 +2943,15 @@ _format_is_param(const char *item)
2872 * @param[out] key where to store the key at - Not NULL. 2943 * @param[out] key where to store the key at - Not NULL.
2873 * @param[out] val where to store the value at - Not NULL. 2944 * @param[out] val where to store the value at - Not NULL.
2874 */ 2945 */
2875static void 2946static Eina_Bool
2876_format_param_parse(const char *item, const char **key, Eina_Tmpstr **val) 2947_format_param_parse(const char *item, const char **key, char **val, Allocator *allocator)
2877{ 2948{
2878 const char *start, *end; 2949 const char *start, *end;
2879 char *tmp, *s, *d; 2950 char *tmp, *s, *d;
2880 size_t len; 2951 size_t len;
2881 2952
2882 start = strchr(item, '='); 2953 start = strchr(item, '=');
2883 if (!start) return ; 2954 if (!start) return EINA_FALSE;
2884 *key = eina_stringshare_add_length(item, start - item); 2955 *key = eina_stringshare_add_length(item, start - item);
2885 start++; /* Advance after the '=' */ 2956 start++; /* Advance after the '=' */
2886 /* If we can find a quote as the first non-space char, 2957 /* If we can find a quote as the first non-space char,
@@ -2906,7 +2977,7 @@ _format_param_parse(const char *item, const char **key, Eina_Tmpstr **val)
2906 if (end) len = end - start; 2977 if (end) len = end - start;
2907 else len = strlen(start); 2978 else len = strlen(start);
2908 2979
2909 tmp = (char*) eina_tmpstr_add_length(start, len); 2980 tmp = _allocator_make_string(allocator, start, len);
2910 if (!tmp) goto end; 2981 if (!tmp) goto end;
2911 2982
2912 for (d = tmp, s = tmp; *s; s++) 2983 for (d = tmp, s = tmp; *s; s++)
@@ -2921,6 +2992,8 @@ _format_param_parse(const char *item, const char **key, Eina_Tmpstr **val)
2921 2992
2922end: 2993end:
2923 *val = tmp; 2994 *val = tmp;
2995
2996 return EINA_TRUE;
2924} 2997}
2925 2998
2926/** 2999/**
@@ -2989,22 +3062,23 @@ _format_fill(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const char
2989 /* get rid of any spaces at the start of the string */ 3062 /* get rid of any spaces at the start of the string */
2990 while (*s == ' ') s++; 3063 while (*s == ' ') s++;
2991 3064
3065 Allocator allocator;
3066 _allocator_init(&allocator);
3067
2992 while ((item = _format_parse(&s))) 3068 while ((item = _format_parse(&s)))
2993 { 3069 {
2994 if (_format_is_param(item)) 3070 const char *key = NULL;
3071 char *val = NULL;
3072 if (_format_param_parse(item, &key, &val, &allocator))
2995 { 3073 {
2996 const char *key = NULL;
2997 Eina_Tmpstr *val = NULL;
2998
2999 _format_param_parse(item, &key, &val);
3000 if ((key) && (val)) _format_command(eo_obj, fmt, key, val); 3074 if ((key) && (val)) _format_command(eo_obj, fmt, key, val);
3001 eina_stringshare_del(key); 3075 eina_stringshare_del(key);
3002 eina_tmpstr_del(val);
3003 } 3076 }
3004 else 3077 else
3005 { 3078 {
3006 /* immediate - not handled here */ 3079 /* immediate - not handled here */
3007 } 3080 }
3081 _allocator_reset(&allocator);
3008 } 3082 }
3009} 3083}
3010 3084
@@ -3715,12 +3789,17 @@ static void
3715_layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, const char *item) 3789_layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, const char *item)
3716{ 3790{
3717 const char *key = NULL; 3791 const char *key = NULL;
3718 Eina_Tmpstr *val = NULL; 3792 char *val = NULL;
3793
3794 Allocator allocator;
3795 _allocator_init(&allocator);
3719 3796
3720 _format_param_parse(item, &key, &val); 3797 _format_param_parse(item, &key, &val, &allocator);
3721 if ((key) && (val)) _format_command(c->obj, fmt, key, val); 3798 if ((key) && (val)) _format_command(c->obj, fmt, key, val);
3722 if (key) eina_stringshare_del(key); 3799 if (key) eina_stringshare_del(key);
3723 if (val) eina_tmpstr_del(val); 3800
3801 _allocator_reset(&allocator);
3802
3724 c->align = fmt->halign; 3803 c->align = fmt->halign;
3725 c->align_auto = fmt->halign_auto; 3804 c->align_auto = fmt->halign_auto;
3726 c->marginl = fmt->margin.l; 3805 c->marginl = fmt->margin.l;