summaryrefslogtreecommitdiff
path: root/src/tests/ecore_strings.c
blob: d76e4c5f5ed425d63d9ca41cf5a4daa0539be0a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <stdlib.h>
#include <string.h>

#include "Ecore_Data.h"

static void ecore_string_free_cb(void *data);

static Ecore_Hash *ecore_strings = NULL;
static int ecore_string_init_count = 0;

/**
 * @defgroup Ecore_String_Group String Instance Functions
 *
 * These functions allow you to store one copy of a string, and use it
 * throughout your program.
 *
 * This is a method to reduce the number of duplicated strings kept in
 * memory. It's pretty common for the same strings to be dynamically
 * allocated repeatedly between applications and libraries, especially in
 * circumstances where you could have multiple copies of a structure that
 * allocates the string. So rather than duplicating and freeing these
 * strings, you request a read-only pointer to an existing string and
 * only incur the overhead of a hash lookup.
 *
 * It sounds like micro-optimizing, but profiling has shown this can have
 * a significant impact as you scale the number of copies up. It improves
 * string creation/destruction speed, reduces memory use and decreases
 * memory fragmentation, so a win all-around.
 */

/**
 * Initialize the ecore string internal structure.
 * @return  Zero on failure, non-zero on successful initialization.
 */
EAPI int
ecore_string_init()
{
   /*
    * No strings have been loaded at this point, so create the hash
    * table for storing string info for later.
    */
   if (!ecore_string_init_count)
     {
        ecore_strings = ecore_hash_new(ecore_str_hash, ecore_str_compare);
        if (!ecore_strings)
           return 0;

        ecore_hash_free_value_cb_set(ecore_strings, ecore_string_free_cb);
     }

   ecore_string_init_count++;

   return 1;
}

/**
 * Retrieves an instance of a string for use in an ecore program.
 * @param   string The string to retrieve an instance of.
 * @return  A pointer to an instance of the string on success.
 *          @c NULL on failure.
 * @ingroup Ecore_String_Group
 */
EAPI const char *
ecore_string_instance(const char *string)
{
   Ecore_String *str;

   CHECK_PARAM_POINTER_RETURN("string", string, NULL);

   /*
    * Check for a previous instance of the string, if not found, create
    * it.
    */
   str = ecore_hash_get(ecore_strings, string);
   if (!str)
     {
        int length;

        /*
         * Allocate and initialize a new string reference.
         */
        length = strlen(string) + 1;

        str =
           (Ecore_String *)malloc(sizeof(Ecore_String) + length * sizeof(char));

        str->string = (char *)(str + 1);
        str->references = 0;

        memcpy(str->string, string, length);

        ecore_hash_set(ecore_strings, str->string, str);
     }

   str->references++;

   return str->string;
}

/**
 * Notes that the given string has lost an instance.
 *
 * It will free the string if no other instances are left.
 *
 * @param   string The given string.
 * @ingroup Ecore_String_Group
 */
EAPI void
ecore_string_release(const char *string)
{
   Ecore_String *str;

   CHECK_PARAM_POINTER("string", string);

   str = ecore_hash_get(ecore_strings, (char *)string);
   if (!str)
      return;

   str->references--;
   if (str->references < 1)
     {
        ecore_hash_remove(ecore_strings, (char *)string);
        FREE(str);
     }
}

EAPI void
ecore_string_hash_dump_graph(void)
{
   ecore_hash_dump_graph(ecore_strings);
}

EAPI void
ecore_string_hash_dump_stats(void)
{
   ecore_hash_dump_stats(ecore_strings);
}

/**
 * Shutdown the ecore string internal structures
 */
EAPI void
ecore_string_shutdown()
{
   --ecore_string_init_count;
   if (!ecore_string_init_count)
     {
        ecore_hash_destroy(ecore_strings);
        ecore_strings = NULL;
     }
}

static void
ecore_string_free_cb(void *data)
{
   Ecore_String *str;

   str = data;
   FREE(str);
}