From dd7595a3475407a7fa96a97393bae8c5220e8762 Mon Sep 17 00:00:00 2001
From: David Walter Seikel
Date: Wed, 4 Jan 2012 18:41:13 +1000
Subject: Add the base Enlightenment Foundation Libraries - eina, eet, evas,
ecore, embryo, and edje.
Note that embryo wont be used, but I'm not sure yet if you can build edje without it.
---
libraries/eina/src/lib/eina_share_common.c | 977 +++++++++++++++++++++++++++++
1 file changed, 977 insertions(+)
create mode 100644 libraries/eina/src/lib/eina_share_common.c
(limited to 'libraries/eina/src/lib/eina_share_common.c')
diff --git a/libraries/eina/src/lib/eina_share_common.c b/libraries/eina/src/lib/eina_share_common.c
new file mode 100644
index 0000000..90e1868
--- /dev/null
+++ b/libraries/eina/src/lib/eina_share_common.c
@@ -0,0 +1,977 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010
+ * Carsten Haitzler,
+ * Jorge Luis Zapata Muga,
+ * Cedric Bail,
+ * Gustavo Sverzut Barbieri
+ * Tom Hacohen
+ * Brett Nash
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see .
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (C) 2008 Peter Wehrfritz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software and its Copyright notices. In addition publicly
+ * documented acknowledgment must be given that this software has been used if no
+ * source code of this software is made available publicly. This includes
+ * acknowledgments in either Copyright notices, Manuals, Publicity and Marketing
+ * documents or any documentation provided with any product containing this
+ * software. This License does not apply to any software that links to the
+ * libraries provided by this software (statically or dynamically), but only to
+ * the software provided.
+ *
+ * Please see the OLD-COPYING.PLAIN for a plain-english explanation of this notice
+ * and it's intent.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+
+#ifdef EFL_HAVE_POSIX_THREADS
+# include
+#endif
+
+#ifdef HAVE_EVIL
+# include
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_hash.h"
+#include "eina_rbtree.h"
+#include "eina_error.h"
+#include "eina_log.h"
+#include "eina_lock.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_share_common.h"
+
+/*============================================================================*
+* Local *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#define EINA_SHARE_COMMON_BUCKETS 256
+#define EINA_SHARE_COMMON_MASK 0xFF
+
+static const char EINA_MAGIC_SHARE_STR[] = "Eina Share";
+static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head";
+
+static int _eina_share_common_count = 0;
+
+#define EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(d, unlock, ...) \
+ do { \
+ if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_SHARE_HEAD)) \
+ { \
+ EINA_MAGIC_FAIL((d), EINA_MAGIC_SHARE_HEAD); \
+ unlock; \
+ return __VA_ARGS__; \
+ } \
+ } while (0)
+
+#define EINA_MAGIC_CHECK_SHARE_COMMON_NODE(d, _node_magic, unlock) \
+ do { \
+ if (!EINA_MAGIC_CHECK((d), _node_magic)) \
+ { \
+ EINA_MAGIC_FAIL((d), _node_magic); \
+ unlock; \
+ } \
+ } while (0)
+
+#ifdef EINA_SHARE_USAGE
+typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population;
+#endif
+
+typedef struct _Eina_Share_Common Eina_Share_Common;
+typedef struct _Eina_Share_Common_Node Eina_Share_Common_Node;
+typedef struct _Eina_Share_Common_Head Eina_Share_Common_Head;
+
+int _eina_share_common_log_dom = -1;
+
+struct _Eina_Share
+{
+ Eina_Share_Common *share;
+ Eina_Magic node_magic;
+#ifdef EINA_SHARE_COMMON_USAGE
+ Eina_Share_Common_Population population;
+ int max_node_population;
+#endif
+};
+
+struct _Eina_Share_Common
+{
+ Eina_Share_Common_Head *buckets[EINA_SHARE_COMMON_BUCKETS];
+
+ EINA_MAGIC
+};
+
+struct _Eina_Share_Common_Node
+{
+ Eina_Share_Common_Node *next;
+
+ EINA_MAGIC
+
+ unsigned int length;
+ unsigned int references;
+ char str[];
+};
+
+struct _Eina_Share_Common_Head
+{
+ EINA_RBTREE;
+ EINA_MAGIC
+
+ int hash;
+
+#ifdef EINA_SHARE_COMMON_USAGE
+ int population;
+#endif
+
+ Eina_Share_Common_Node *head;
+ Eina_Share_Common_Node builtin_node;
+};
+
+Eina_Bool _share_common_threads_activated = EINA_FALSE;
+
+static Eina_Lock _mutex_big;
+
+#ifdef EINA_SHARE_COMMON_USAGE
+struct _Eina_Share_Common_Population
+{
+ int count;
+ int max;
+};
+
+static Eina_Share_Common_Population population = { 0, 0 };
+
+static Eina_Share_Common_Population population_group[4] =
+{
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+};
+
+static void
+_eina_share_common_population_init(Eina_Share *share)
+{
+ unsigned int i;
+
+ for (i = 0;
+ i < sizeof (share->population_group) /
+ sizeof (share->population_group[0]);
+ ++i)
+ {
+ share->population_group[i].count = 0;
+ share->population_group[i].max = 0;
+ }
+}
+
+static void
+_eina_share_common_population_shutdown(Eina_Share *share)
+{
+ unsigned int i;
+
+ share->max_node_population = 0;
+ share->population.count = 0;
+ share->population.max = 0;
+
+ for (i = 0;
+ i < sizeof (share->population_group) /
+ sizeof (share->population_group[0]);
+ ++i)
+ {
+ share->population_group[i].count = 0;
+ share->population_group[i].max = 0;
+ }
+}
+
+static void
+_eina_share_common_population_stats(Eina_Share *share)
+{
+ unsigned int i;
+
+ fprintf(stderr, "eina share_common statistic:\n");
+ fprintf(stderr,
+ " * maximum shared strings : %i\n",
+ share->population.max);
+ fprintf(stderr,
+ " * maximum shared strings per node : %i\n",
+ share->max_node_population);
+
+ for (i = 0;
+ i < sizeof (share->population_group) /
+ sizeof (share->population_group[0]);
+ ++i)
+ fprintf(stderr,
+ "DDD: %i strings of length %i, max strings: %i\n",
+ share->population_group[i].count,
+ i,
+ share->population_group[i].max);
+}
+
+void
+eina_share_common_population_add(Eina_Share *share, int slen)
+{
+ eina_lock_take(&_mutex_big);
+
+ share->population.count++;
+ if (share->population.count > share->population.max)
+ share->population.max = share->population.count;
+
+ if (slen < 4)
+ {
+ share->population_group[slen].count++;
+ if (share->population_group[slen].count >
+ share->population_group[slen].max)
+ share->population_group[slen].max =
+ share->population_group[slen].count;
+ }
+
+ eina_lock_release(&_mutex_big);
+}
+
+void
+eina_share_common_population_del(Eina_Share *share, int slen)
+{
+ eina_lock_take(&_mutex_big);
+
+ share->population.count--;
+ if (slen < 4)
+ share->population_group[slen].count--;
+
+ eina_lock_release(&_mutex_big);
+}
+
+static void
+_eina_share_common_population_head_init(Eina_Share *share,
+ Eina_Share_Common_Head *head)
+{
+ head->population = 1;
+}
+
+static void
+_eina_share_common_population_head_add(Eina_Share *share,
+ Eina_Share_Common_Head *head)
+{
+ head->population++;
+ if (head->population > share->max_node_population)
+ share->max_node_population = head->population;
+}
+
+static void
+_eina_share_common_population_head_del(Eina_Share *share,
+ Eina_Share_Common_Head *head)
+{
+ head->population--;
+}
+
+#else /* EINA_SHARE_COMMON_USAGE undefined */
+
+static void _eina_share_common_population_init(__UNUSED__ Eina_Share *share) {
+}
+static void _eina_share_common_population_shutdown(__UNUSED__ Eina_Share *share)
+{
+}
+static void _eina_share_common_population_stats(__UNUSED__ Eina_Share *share) {
+}
+void eina_share_common_population_add(__UNUSED__ Eina_Share *share,
+ __UNUSED__ int slen) {
+}
+void eina_share_common_population_del(__UNUSED__ Eina_Share *share,
+ __UNUSED__ int slen) {
+}
+static void _eina_share_common_population_head_init(
+ __UNUSED__ Eina_Share *share,
+ __UNUSED__ Eina_Share_Common_Head *head) {
+}
+static void _eina_share_common_population_head_add(
+ __UNUSED__ Eina_Share *share,
+ __UNUSED__
+ Eina_Share_Common_Head *head) {
+}
+static void _eina_share_common_population_head_del(
+ __UNUSED__ Eina_Share *share,
+ __UNUSED__
+ Eina_Share_Common_Head *head) {
+}
+#endif
+
+static int
+_eina_share_common_cmp(const Eina_Share_Common_Head *ed,
+ const int *hash,
+ __UNUSED__ int length,
+ __UNUSED__ void *data)
+{
+ EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, , 0);
+
+ return ed->hash - *hash;
+}
+
+static Eina_Rbtree_Direction
+_eina_share_common_node(const Eina_Share_Common_Head *left,
+ const Eina_Share_Common_Head *right,
+ __UNUSED__ void *data)
+{
+ EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(left, , 0);
+ EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(right, , 0);
+
+ if (left->hash - right->hash < 0)
+ return EINA_RBTREE_LEFT;
+
+ return EINA_RBTREE_RIGHT;
+}
+
+static void
+_eina_share_common_head_free(Eina_Share_Common_Head *ed, __UNUSED__ void *data)
+{
+ EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, );
+
+ while (ed->head)
+ {
+ Eina_Share_Common_Node *el = ed->head;
+
+ ed->head = ed->head->next;
+ if (el != &ed->builtin_node)
+ MAGIC_FREE(el);
+ }
+ MAGIC_FREE(ed);
+}
+
+static void
+_eina_share_common_node_init(Eina_Share_Common_Node *node,
+ const char *str,
+ int slen,
+ unsigned int null_size,
+ Eina_Magic node_magic)
+{
+ EINA_MAGIC_SET(node, node_magic);
+ node->references = 1;
+ node->length = slen;
+ memcpy(node->str, str, slen);
+ memset(node->str + slen, 0, null_size); /* Nullify the null */
+
+ (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
+}
+
+static Eina_Share_Common_Head *
+_eina_share_common_head_alloc(int slen)
+{
+ Eina_Share_Common_Head *head;
+ const size_t head_size = offsetof(Eina_Share_Common_Head, builtin_node.str);
+
+ head = malloc(head_size + slen);
+ if (!head)
+ eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+
+ return head;
+}
+
+static const char *
+_eina_share_common_add_head(Eina_Share *share,
+ Eina_Share_Common_Head **p_bucket,
+ int hash,
+ const char *str,
+ unsigned int slen,
+ unsigned int null_size)
+{
+ Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
+ Eina_Share_Common_Head *head;
+
+ head = _eina_share_common_head_alloc(slen + null_size);
+ if (!head)
+ return NULL;
+
+ EINA_MAGIC_SET(head, EINA_MAGIC_SHARE_HEAD);
+ head->hash = hash;
+ head->head = &head->builtin_node;
+ _eina_share_common_node_init(head->head,
+ str,
+ slen,
+ null_size,
+ share->node_magic);
+ head->head->next = NULL;
+
+ _eina_share_common_population_head_init(share, head);
+
+ *p_tree = eina_rbtree_inline_insert
+ (*p_tree, EINA_RBTREE_GET(head),
+ EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
+
+ return head->head->str;
+}
+
+static void
+_eina_share_common_del_head(Eina_Share_Common_Head **p_bucket,
+ Eina_Share_Common_Head *head)
+{
+ Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
+
+ *p_tree = eina_rbtree_inline_remove
+ (*p_tree, EINA_RBTREE_GET(head),
+ EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
+
+ MAGIC_FREE(head);
+}
+
+
+static inline Eina_Bool
+_eina_share_common_node_eq(const Eina_Share_Common_Node *node,
+ const char *str,
+ unsigned int slen)
+{
+ return ((node->length == slen) &&
+ (memcmp(node->str, str, slen) == 0));
+}
+
+static Eina_Share_Common_Node *
+_eina_share_common_head_find(Eina_Share_Common_Head *head,
+ const char *str,
+ unsigned int slen)
+{
+ Eina_Share_Common_Node *node, *prev;
+
+ node = head->head;
+ if (_eina_share_common_node_eq(node, str, slen))
+ return node;
+
+ prev = node;
+ node = node->next;
+ for (; node; prev = node, node = node->next)
+ if (_eina_share_common_node_eq(node, str, slen))
+ {
+ /* promote node, make hot items be at the beginning */
+ prev->next = node->next;
+ node->next = head->head;
+ head->head = node;
+ return node;
+ }
+
+ return NULL;
+}
+
+static Eina_Bool
+_eina_share_common_head_remove_node(Eina_Share_Common_Head *head,
+ const Eina_Share_Common_Node *node)
+{
+ Eina_Share_Common_Node *cur, *prev;
+
+ if (head->head == node)
+ {
+ head->head = node->next;
+ return 1;
+ }
+
+ prev = head->head;
+ cur = head->head->next;
+ for (; cur; prev = cur, cur = cur->next)
+ if (cur == node)
+ {
+ prev->next = cur->next;
+ return 1;
+ }
+
+ return 0;
+}
+
+static Eina_Share_Common_Head *
+_eina_share_common_find_hash(Eina_Share_Common_Head *bucket, int hash)
+{
+ return (Eina_Share_Common_Head *)eina_rbtree_inline_lookup
+ (EINA_RBTREE_GET(bucket), &hash, 0,
+ EINA_RBTREE_CMP_KEY_CB(_eina_share_common_cmp), NULL);
+}
+
+static Eina_Share_Common_Node *
+_eina_share_common_node_alloc(unsigned int slen, unsigned int null_size)
+{
+ Eina_Share_Common_Node *node;
+ const size_t node_size = offsetof(Eina_Share_Common_Node, str);
+
+ node = malloc(node_size + slen + null_size);
+ if (!node)
+ eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+
+ return node;
+}
+
+static Eina_Share_Common_Node *
+_eina_share_common_node_from_str(const char *str, Eina_Magic node_magic)
+{
+ Eina_Share_Common_Node *node;
+ const size_t offset = offsetof(Eina_Share_Common_Node, str);
+
+ node = (Eina_Share_Common_Node *)(str - offset);
+ EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL);
+ return node;
+
+ (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
+}
+
+static Eina_Bool
+eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__,
+ Eina_Share_Common_Head *head,
+ struct dumpinfo *fdata)
+{
+ Eina_Share_Common_Node *node;
+
+ fdata->used += sizeof(Eina_Share_Common_Head);
+ for (node = head->head; node; node = node->next)
+ {
+ printf("DDD: %5i %5i ", node->length, node->references);
+ printf("'%.*s'\n", node->length, ((char *)node) + sizeof(Eina_Share_Common_Node));
+ fdata->used += sizeof(Eina_Share_Common_Node);
+ fdata->used += node->length;
+ fdata->saved += (node->references - 1) * node->length;
+ fdata->dups += node->references - 1;
+ fdata->unique++;
+ }
+
+ return EINA_TRUE;
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+* Global *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the share_common module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_share_common_init(Eina_Share **_share,
+ Eina_Magic node_magic,
+ const char *node_magic_STR)
+{
+ Eina_Share *share;
+
+ share = *_share = calloc(sizeof(Eina_Share), 1);
+ if (!share) goto on_error;
+
+ if (_eina_share_common_log_dom < 0) /*Only register if not already */
+ _eina_share_common_log_dom = eina_log_domain_register(
+ "eina_share",
+ EINA_LOG_COLOR_DEFAULT);
+
+ if (_eina_share_common_log_dom < 0)
+ {
+ EINA_LOG_ERR("Could not register log domain: eina_share_common");
+ goto on_error;
+ }
+
+ share->share = calloc(1, sizeof(Eina_Share_Common));
+ if (!share->share)
+ {
+ if (_eina_share_common_log_dom > 0)
+ {
+ eina_log_domain_unregister(_eina_share_common_log_dom);
+ _eina_share_common_log_dom = -1;
+ }
+
+ goto on_error;
+ }
+
+ share->node_magic = node_magic;
+#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
+ EMS(EINA_MAGIC_SHARE);
+ EMS(EINA_MAGIC_SHARE_HEAD);
+ EMS(node_magic);
+#undef EMS
+ EINA_MAGIC_SET(share->share, EINA_MAGIC_SHARE);
+
+ _eina_share_common_population_init(share);
+
+ /* below is the common part among other all eina_share_common user */
+ if (_eina_share_common_count++ != 0)
+ return EINA_TRUE;
+
+ eina_lock_new(&_mutex_big);
+ return EINA_TRUE;
+
+ on_error:
+ _eina_share_common_count--;
+ return EINA_FALSE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the share_common module set up by
+ * eina_share_common_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_share_common_shutdown(Eina_Share **_share)
+{
+ unsigned int i;
+ Eina_Share *share = *_share;
+
+ eina_lock_take(&_mutex_big);
+
+ _eina_share_common_population_stats(share);
+
+ /* remove any string still in the table */
+ for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
+ {
+ eina_rbtree_delete(EINA_RBTREE_GET(
+ share->share->buckets[i]),
+ EINA_RBTREE_FREE_CB(
+ _eina_share_common_head_free), NULL);
+ share->share->buckets[i] = NULL;
+ }
+ MAGIC_FREE(share->share);
+
+ _eina_share_common_population_shutdown(share);
+ if (_eina_share_common_log_dom > 0) /* Only free if necessary */
+ {
+ eina_log_domain_unregister(_eina_share_common_log_dom);
+ _eina_share_common_log_dom = -1;
+ }
+
+ eina_lock_release(&_mutex_big);
+
+ free(*_share);
+ *_share = NULL;
+
+ /* below is the common part among other all eina_share_common user */
+ if (--_eina_share_common_count != 0)
+ return EINA_TRUE;
+
+ eina_lock_free(&_mutex_big);
+
+ return EINA_TRUE;
+}
+
+#ifdef EFL_HAVE_THREADS
+
+/**
+ * @internal
+ * @brief Activate the share_common mutexes.
+ *
+ * This function activate the mutexes in the eina share_common module. It is called by
+ * eina_threads_init().
+ *
+ * @see eina_threads_init()
+ */
+void
+eina_share_common_threads_init(void)
+{
+ _share_common_threads_activated = EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the share_common mutexes.
+ *
+ * This function shuts down the mutexes in the share_common module.
+ * It is called by eina_threads_shutdown().
+ *
+ * @see eina_threads_shutdown()
+ */
+void
+eina_share_common_threads_shutdown(void)
+{
+ _share_common_threads_activated = EINA_FALSE;
+}
+
+#endif
+
+/*============================================================================*
+* API *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+const char *
+eina_share_common_add_length(Eina_Share *share,
+ const char *str,
+ unsigned int slen,
+ unsigned int null_size)
+{
+ Eina_Share_Common_Head **p_bucket, *ed;
+ Eina_Share_Common_Node *el;
+ int hash_num, hash;
+
+ if (!str)
+ return NULL;
+
+ eina_share_common_population_add(share, slen);
+
+ if (slen <= 0)
+ return NULL;
+
+ hash = eina_hash_superfast(str, slen);
+ hash_num = hash & 0xFF;
+ hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
+
+ eina_lock_take(&_mutex_big);
+ p_bucket = share->share->buckets + hash_num;
+
+ ed = _eina_share_common_find_hash(*p_bucket, hash);
+ if (!ed)
+ {
+ const char *s = _eina_share_common_add_head(share,
+ p_bucket,
+ hash,
+ str,
+ slen,
+ null_size);
+ eina_lock_release(&_mutex_big);
+ return s;
+ }
+
+ EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), NULL);
+
+ el = _eina_share_common_head_find(ed, str, slen);
+ if (el)
+ {
+ EINA_MAGIC_CHECK_SHARE_COMMON_NODE(el,
+ share->node_magic,
+ eina_lock_release(&_mutex_big));
+ el->references++;
+ eina_lock_release(&_mutex_big);
+ return el->str;
+ }
+
+ el = _eina_share_common_node_alloc(slen, null_size);
+ if (!el)
+ {
+ eina_lock_release(&_mutex_big);
+ return NULL;
+ }
+
+ _eina_share_common_node_init(el, str, slen, null_size, share->node_magic);
+ el->next = ed->head;
+ ed->head = el;
+ _eina_share_common_population_head_add(share, ed);
+
+ eina_lock_release(&_mutex_big);
+
+ return el->str;
+}
+
+const char *
+eina_share_common_ref(Eina_Share *share, const char *str)
+{
+ Eina_Share_Common_Node *node;
+
+ if (!str)
+ return NULL;
+
+ eina_lock_take(&_mutex_big);
+ node = _eina_share_common_node_from_str(str, share->node_magic);
+ if (!node)
+ {
+ eina_lock_release(&_mutex_big);
+ return str;
+ }
+ node->references++;
+
+ eina_lock_release(&_mutex_big);
+
+ eina_share_common_population_add(share, node->length);
+
+ return str;
+}
+
+
+void
+eina_share_common_del(Eina_Share *share, const char *str)
+{
+ unsigned int slen;
+ Eina_Share_Common_Head *ed;
+ Eina_Share_Common_Head **p_bucket;
+ Eina_Share_Common_Node *node;
+ int hash_num, hash;
+
+ if (!str)
+ return;
+
+ eina_lock_take(&_mutex_big);
+
+ node = _eina_share_common_node_from_str(str, share->node_magic);
+ if (!node)
+ goto on_error;
+
+ slen = node->length;
+ eina_share_common_population_del(share, slen);
+ if (node->references > 1)
+ {
+ node->references--;
+ eina_lock_release(&_mutex_big);
+ return;
+ }
+
+ node->references = 0;
+
+ hash = eina_hash_superfast(str, slen);
+ hash_num = hash & 0xFF;
+ hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
+
+ p_bucket = share->share->buckets + hash_num;
+ ed = _eina_share_common_find_hash(*p_bucket, hash);
+ if (!ed)
+ goto on_error;
+
+ EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big));
+
+ if (!_eina_share_common_head_remove_node(ed, node))
+ goto on_error;
+
+ if (node != &ed->builtin_node)
+ MAGIC_FREE(node);
+
+ if (!ed->head)
+ _eina_share_common_del_head(p_bucket, ed);
+ else
+ _eina_share_common_population_head_del(share, ed);
+
+ eina_lock_release(&_mutex_big);
+
+ return;
+
+on_error:
+ eina_lock_release(&_mutex_big);
+ /* possible segfault happened before here, but... */
+ CRITICAL("EEEK trying to del non-shared share_common \"%s\"", str);
+}
+
+int
+eina_share_common_length(__UNUSED__ Eina_Share *share, const char *str)
+{
+ const Eina_Share_Common_Node *node;
+
+ if (!str)
+ return -1;
+
+ node = _eina_share_common_node_from_str(str, share->node_magic);
+ if (!node) return 0;
+ return node->length;
+}
+
+void
+eina_share_common_dump(Eina_Share *share, void (*additional_dump)(
+ struct dumpinfo *), int used)
+{
+ Eina_Iterator *it;
+ unsigned int i;
+ struct dumpinfo di;
+
+ if (!share)
+ return;
+
+ di.used = used;
+ di.saved = 0;
+ di.dups = 0;
+ di.unique = 0;
+ printf("DDD: len ref string\n");
+ printf("DDD:-------------------\n");
+
+ eina_lock_take(&_mutex_big);
+ for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
+ {
+ if (!share->share->buckets[i])
+ {
+ continue; // printf("DDD: BUCKET # %i (HEAD=%i, NODE=%i)\n", i,
+
+ }
+
+// sizeof(Eina_Share_Common_Head), sizeof(Eina_Share_Common_Node));
+ it = eina_rbtree_iterator_prefix(
+ (Eina_Rbtree *)share->share->buckets[i]);
+ eina_iterator_foreach(it, EINA_EACH_CB(eina_iterator_array_check), &di);
+ eina_iterator_free(it);
+ }
+ if (additional_dump)
+ additional_dump(&di);
+
+#ifdef EINA_SHARE_COMMON_USAGE
+ /* One character strings are not counted in the hash. */
+ di.saved += share->population_group[0].count * sizeof(char);
+ di.saved += share->population_group[1].count * sizeof(char) * 2;
+#endif
+ printf("DDD:-------------------\n");
+ printf("DDD: usage (bytes) = %i, saved = %i (%3.0f%%)\n",
+ di.used, di.saved, di.used ? (di.saved * 100.0 / di.used) : 0.0);
+ printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n",
+ di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0);
+
+#ifdef EINA_SHARE_COMMON_USAGE
+ printf("DDD: Allocated strings: %i\n", share->population.count);
+ printf("DDD: Max allocated strings: %i\n", share->population.max);
+
+ for (i = 0;
+ i < sizeof (share->population_group) /
+ sizeof (share->population_group[0]);
+ ++i)
+ fprintf(stderr,
+ "DDD: %i strings of length %i, max strings: %i\n",
+ share->population_group[i].count,
+ i,
+ share->population_group[i].max);
+#endif
+
+ eina_lock_release(&_mutex_big);
+}
+
+/**
+ * @endcond
+ */
--
cgit v1.1