Also modified Eina_Stringshare to share most of the code with the two above. Added Magics for Eina_UStrbuf as well as for UStringshare/Binshare. SVN revision: 50533devs/devilhorns/wayland_egl
parent
270f765c91
commit
3675a5f02b
15 changed files with 1797 additions and 811 deletions
@ -0,0 +1,85 @@ |
||||
/* EINA - EFL data type library
|
||||
* Copyright (C) 2002-2008 Carsten Haitzler, Jorge Luis Zapata Muga, Cedric Bail |
||||
* |
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
#ifndef EINA_BINSHARE_H_ |
||||
#define EINA_BINSHARE_H_ |
||||
|
||||
#include "eina_types.h" |
||||
|
||||
/**
|
||||
* @addtogroup Eina_Data_Types_Group Data Types |
||||
* |
||||
* @{ |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup Eina_Binshare_Group Binary Share |
||||
* |
||||
* @{ |
||||
*/ |
||||
|
||||
EAPI Eina_Bool eina_binshare_init(void); |
||||
EAPI Eina_Bool eina_binshare_shutdown(void); |
||||
EAPI const char *eina_binshare_add_length(const char *str, unsigned int slen) EINA_WARN_UNUSED_RESULT; |
||||
EAPI const char *eina_binshare_add(const char *str) EINA_WARN_UNUSED_RESULT; |
||||
EAPI const char *eina_binshare_ref(const char *str); |
||||
EAPI void eina_binshare_del(const char *str); |
||||
EAPI int eina_binshare_length(const char *str) EINA_CONST EINA_WARN_UNUSED_RESULT; |
||||
EAPI void eina_binshare_dump(void); |
||||
|
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
||||
#endif /* EINA_STRINGSHARE_H_ */ |
@ -0,0 +1,92 @@ |
||||
/* EINA - EFL data type library |
||||
* Copyright (C) 2002-2008 Gustavo Sverzut Barbieri |
||||
Tom Hacohen |
||||
* |
||||
* 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 <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
#ifndef EINA_USTRINGSHARE_INLINE_H_ |
||||
#define EINA_USTRINGSHARE_INLINE_H_ |
||||
|
||||
#include "eina_unicode.h" |
||||
#include "eina_ustringshare.h" |
||||
/** |
||||
* @addtogroup Eina_UStringshare_Group UStringshare |
||||
* |
||||
* @{ |
||||
*/ |
||||
|
||||
/** |
||||
* Replace the previously stringshared pointer with new content. |
||||
* |
||||
* The string pointed by @a p_str should be previously stringshared or |
||||
* @c NULL and it will be eina_ustringshare_del(). The new string will |
||||
* be passed to eina_ustringshare_add() and then assigned to @c *p_str. |
||||
* |
||||
* @param p_str pointer to the stringhare to be replaced. Must not be |
||||
* @c NULL, but @c *p_str may be @c NULL as it is a valid |
||||
* stringshare handle. |
||||
* @param news new string to be stringshared, may be @c NULL. |
||||
* |
||||
* @return #EINA_TRUE if the strings were different and thus replaced, |
||||
* #EINA_FALSE if the strings were the same after shared. |
||||
*/ |
||||
static inline Eina_Bool |
||||
eina_ustringshare_replace(const Eina_Unicode **p_str, const Eina_Unicode *news) |
||||
{ |
||||
if (*p_str == news) return EINA_FALSE; |
||||
|
||||
news = eina_ustringshare_add(news); |
||||
eina_ustringshare_del(*p_str); |
||||
if (*p_str == news) |
||||
return EINA_FALSE; |
||||
*p_str = news; |
||||
return EINA_TRUE; |
||||
} |
||||
|
||||
/** |
||||
* Replace the previously stringshared pointer with a new content. |
||||
* |
||||
* The string pointed by @a p_str should be previously stringshared or |
||||
* @c NULL and it will be eina_ustringshare_del(). The new string will |
||||
* be passed to eina_ustringshare_add_length() and then assigned to @c *p_str. |
||||
* |
||||
* @param p_str pointer to the stringhare to be replaced. Must not be |
||||
* @c NULL, but @c *p_str may be @c NULL as it is a valid |
||||
* stringshare handle. |
||||
* @param news new string to be stringshared, may be @c NULL. |
||||
* @param slen The string size (<= strlen(str)). |
||||
* |
||||
* @return #EINA_TRUE if the strings were different and thus replaced, |
||||
* #EINA_FALSE if the strings were the same after shared. |
||||
*/ |
||||
static inline Eina_Bool |
||||
eina_ustringshare_replace_length(const Eina_Unicode **p_str, const Eina_Unicode *news, unsigned int slen) |
||||
{ |
||||
if (*p_str == news) return EINA_FALSE; |
||||
|
||||
news = eina_ustringshare_add_length(news, slen); |
||||
eina_ustringshare_del(*p_str); |
||||
if (*p_str == news) |
||||
return EINA_FALSE; |
||||
*p_str = news; |
||||
return EINA_TRUE; |
||||
} |
||||
|
||||
/** |
||||
* @} |
||||
*/ |
||||
|
||||
#endif /* EINA_USTRINGSHARE_INLINE_H_ */ |
@ -0,0 +1,89 @@ |
||||
/* EINA - EFL data type library
|
||||
* Copyright (C) 2002-2008 Carsten Haitzler, Jorge Luis Zapata Muga, Cedric Bail |
||||
* |
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
#ifndef EINA_USTRINGSHARE_H_ |
||||
#define EINA_USTRINGSHARE_H_ |
||||
|
||||
#include "eina_types.h" |
||||
#include "eina_unicode.h" |
||||
|
||||
/**
|
||||
* @addtogroup Eina_Data_Types_Group Data Types |
||||
* |
||||
* @{ |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup Eina_UStringshare_Group Unicode Stringshare |
||||
* |
||||
* @{ |
||||
*/ |
||||
|
||||
EAPI const Eina_Unicode *eina_ustringshare_add_length(const Eina_Unicode *str, unsigned int slen) EINA_WARN_UNUSED_RESULT; |
||||
EAPI const Eina_Unicode *eina_ustringshare_add(const Eina_Unicode *str) EINA_WARN_UNUSED_RESULT; |
||||
EAPI const Eina_Unicode *eina_ustringshare_ref(const Eina_Unicode *str); |
||||
EAPI void eina_ustringshare_del(const Eina_Unicode *str); |
||||
EAPI int eina_ustringshare_strlen(const Eina_Unicode *str) EINA_CONST EINA_WARN_UNUSED_RESULT; |
||||
EAPI void eina_ustringshare_dump(void); |
||||
|
||||
static inline Eina_Bool eina_ustringshare_replace(const Eina_Unicode **p_str, const Eina_Unicode *news) EINA_ARG_NONNULL(1); |
||||
static inline Eina_Bool eina_ustringshare_replace_length(const Eina_Unicode **p_str, const Eina_Unicode *news, unsigned int slen) EINA_ARG_NONNULL(1); |
||||
|
||||
#include "eina_inline_ustringshare.x" |
||||
|
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
||||
#endif /* EINA_STRINGSHARE_H_ */ |
@ -0,0 +1,212 @@ |
||||
/*
|
||||
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 |
||||
*/ |
||||
/* EINA - EFL data type library
|
||||
* Copyright (C) 2002-2008 Carsten Haitzler, |
||||
* Jorge Luis Zapata Muga, |
||||
* Cedric Bail, |
||||
* Gustavo Sverzut Barbieri |
||||
* Tom Hacohen |
||||
* |
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/ |
||||
/**
|
||||
* @page tutorial_binshare_page Binary Share Tutorial |
||||
* |
||||
* Should call eina_binshare_init() before usage and eina_binshare_shutdown() after. |
||||
* to be written... |
||||
* |
||||
*/ |
||||
|
||||
#include "eina_share_common.h" |
||||
#include "eina_unicode.h" |
||||
#include "eina_private.h" |
||||
|
||||
/* The actual share */ |
||||
static Eina_Share *share; |
||||
static const char EINA_MAGIC_BINSHARE_NODE_STR[] = "Eina Binshare Node"; |
||||
|
||||
/*============================================================================*
|
||||
* 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() |
||||
*/ |
||||
EAPI Eina_Bool |
||||
eina_binshare_init(void) |
||||
{ |
||||
return eina_share_common_init(&share, EINA_MAGIC_BINSHARE_NODE, EINA_MAGIC_BINSHARE_NODE_STR); |
||||
} |
||||
|
||||
/**
|
||||
* @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() |
||||
*/ |
||||
EAPI Eina_Bool |
||||
eina_binshare_shutdown(void) |
||||
{ |
||||
Eina_Bool ret; |
||||
ret = eina_share_common_shutdown(&share); |
||||
return ret; |
||||
} |
||||
|
||||
/*============================================================================*
|
||||
* API * |
||||
*============================================================================*/ |
||||
/**
|
||||
* @addtogroup Eina_Binshare_Group Binary Share |
||||
* |
||||
* 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. |
||||
* |
||||
* For more information, you can look at the @ref tutorial_binshare_page. |
||||
* |
||||
* @{ |
||||
*/ |
||||
|
||||
/**
|
||||
* @brief Note that the given string has lost an instance. |
||||
* |
||||
* @param str string The given string. |
||||
* |
||||
* This function decreases the reference counter associated to @p str |
||||
* if it exists. If that counter reaches 0, the memory associated to |
||||
* @p str is freed. If @p str is NULL, the function returns |
||||
* immediatly. |
||||
* |
||||
* Note that if the given pointer is not shared or NULL, bad things |
||||
* will happen, likely a segmentation fault. |
||||
*/ |
||||
EAPI void |
||||
eina_binshare_del(const char *str, unsigned int slen) |
||||
{ |
||||
if (!str) |
||||
return; |
||||
eina_share_common_del(share,(const char *) str, slen); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Retrieve an instance of a string for use in a program. |
||||
* |
||||
* @param str The binary string to retrieve an instance of. |
||||
* @param slen The byte size |
||||
* @return A pointer to an instance of the string on success. |
||||
* @c NULL on failure. |
||||
* |
||||
* This function retrieves an instance of @p str. If @p str is |
||||
* @c NULL, then @c NULL is returned. If @p str is already stored, it |
||||
* is just returned and its reference counter is increased. Otherwise |
||||
* it is added to the strings to be searched and a duplicated string |
||||
* of @p str is returned. |
||||
* |
||||
* This function does not check string size, but uses the |
||||
* exact given size. This can be used to share_common part of a larger |
||||
* buffer or substring. |
||||
* |
||||
* @see eina_binshare_add() |
||||
*/ |
||||
EAPI const char * |
||||
eina_binshare_add_length(const char *str, unsigned int slen) |
||||
{ |
||||
return (const char *) eina_share_common_add_length(share,(const char *) str, (slen + 1) * sizeof(char), 0); |
||||
} |
||||
|
||||
/**
|
||||
* Increment references of the given shared string. |
||||
* |
||||
* @param str The shared string. |
||||
* @return A pointer to an instance of the string on success. |
||||
* @c NULL on failure. |
||||
* |
||||
* This is similar to eina_share_common_add(), but it's faster since it will |
||||
* avoid lookups if possible, but on the down side it requires the parameter |
||||
* to be shared before, in other words, it must be the return of a previous |
||||
* eina_binshare_add(). |
||||
* |
||||
* There is no unref since this is the work of eina_binshare_del(). |
||||
*/ |
||||
EAPI const char * |
||||
eina_binshare_ref(const char *str) |
||||
{ |
||||
if (!str)
|
||||
{ |
||||
return (const char *) eina_share_common_ref(share, (const char *) str); |
||||
} |
||||
return (const char *) eina_share_common_ref(share, (const char *) str); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Note that the given string @b must be shared. |
||||
* |
||||
* @param str the shared string to know the length. It is safe to |
||||
* give NULL, in that case -1 is returned. |
||||
* |
||||
* This function is a cheap way to known the length of a shared |
||||
* string. Note that if the given pointer is not shared, bad |
||||
* things will happen, likely a segmentation fault. If in doubt, try |
||||
* strlen(). |
||||
*/ |
||||
EAPI int |
||||
eina_binshare_length(const char *str) |
||||
{ |
||||
return eina_share_common_length(share, (const char *) str); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Dump the contents of the share_common. |
||||
* |
||||
* This function dumps all strings in the share_common to stdout with a |
||||
* DDD: prefix per line and a memory usage summary. |
||||
*/ |
||||
EAPI void |
||||
eina_binshare_dump(void) |
||||
{ |
||||
eina_share_common_dump(share, NULL, 0); |
||||
} |
||||
|
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
@ -0,0 +1,863 @@ |
||||
/*
|
||||
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 |
||||
*/ |
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
* |
||||
* 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 <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stddef.h> |
||||
|
||||
#ifdef EFL_HAVE_POSIX_THREADS |
||||
# include <pthread.h> |
||||
#endif |
||||
|
||||
#ifdef HAVE_EVIL |
||||
# include <Evil.h> |
||||
#endif |
||||
|
||||
#include "eina_config.h" |
||||
#include "eina_private.h" |
||||
#include "eina_hash.h" |
||||
#include "eina_rbtree.h" |
||||
#include "eina_error.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"; |
||||
|
||||
|
||||
#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)) \
|
||||
{ \
|
||||
unlock; \
|
||||
EINA_MAGIC_FAIL((d), _node_magic); \
|
||||
} \
|
||||
} 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; |
||||
}; |
||||
|
||||
#ifdef EFL_HAVE_THREADS |
||||
Eina_Bool _share_common_threads_activated = EINA_FALSE; |
||||
|
||||
# ifdef EFL_HAVE_POSIX_THREADS |
||||
static pthread_mutex_t _mutex_big = PTHREAD_MUTEX_INITIALIZER; |
||||
# define SHARE_COMMON_LOCK_BIG() if(_share_common_threads_activated) pthread_mutex_lock(&_mutex_big) |
||||
# define SHARE_COMMON_UNLOCK_BIG() if(_share_common_threads_activated) pthread_mutex_unlock(&_mutex_big) |
||||
# else /* EFL_HAVE_WIN32_THREADS */ |
||||
static HANDLE _mutex_big = NULL; |
||||
# define SHARE_COMMON_LOCK_BIG() if(_share_common_threads_activated) WaitForSingleObject(_mutex_big, INFINITE) |
||||
# define SHARE_COMMON_UNLOCK_BIG() if(_share_common_threads_activated) ReleaseMutex(_mutex_big) |
||||
|
||||
# endif /* EFL_HAVE_WIN32_THREADS */ |
||||
#else /* EFL_HAVE_THREADS */ |
||||
# define SHARE_COMMON_LOCK_BIG() do {} while (0) |
||||
# define SHARE_COMMON_UNLOCK_BIG() do {} while (0) |
||||
#endif |
||||
|
||||
#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) |
||||
{ |
||||
SHARE_COMMON_LOCK_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; |
||||
} |
||||
|
||||
SHARE_COMMON_UNLOCK_BIG(); |
||||
} |
||||
|
||||
void |
||||
eina_share_common_population_del(Eina_Share *share, int slen) |
||||
{ |
||||
SHARE_COMMON_LOCK_BIG(); |
||||
|
||||
share->population.count--; |
||||
if (slen < 4) |
||||
share->population_group[slen].count--; |
||||
|
||||
SHARE_COMMON_UNLOCK_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 */ |
||||
} |
||||
|
||||
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 != NULL; 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 != NULL; 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, ); |
||||
return node; |
||||
} |
||||
|
||||
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; |
||||
|
||||
SHARE_COMMON_LOCK_BIG(); |
||||
|
||||
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", ((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++; |
||||
} |
||||
|
||||
SHARE_COMMON_UNLOCK_BIG(); |
||||
|
||||
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) |
||||
return EINA_FALSE; |
||||
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"); |
||||
return EINA_FALSE; |
||||
} |
||||
|
||||
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; |
||||
} |
||||
return EINA_FALSE; |
||||
}
|
||||
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); |
||||
return EINA_TRUE; |
||||
} |
||||
|
||||
/**
|
||||
* @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; |
||||
|
||||
SHARE_COMMON_LOCK_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; |
||||
} |
||||
|
||||
SHARE_COMMON_UNLOCK_BIG(); |
||||
|
||||
free(*_share); |
||||
*_share = NULL; |
||||
return EINA_TRUE; |
||||
} |
||||
|
||||
#ifdef EFL_HAVE_THREADS |
||||
|
||||
/**
|
||||
* @internal |
||||
* @brief Activate the share_common mutexs. |
||||
* |
||||
* This function activate the mutexs in the eina share_common module. It is called by |
||||
* eina_thread_init(). |
||||
* |
||||
* @see eina_thread_init() |
||||
*/ |
||||
void |
||||
eina_share_common_threads_init(void) |
||||
{ |
||||
_share_common_threads_activated = EINA_TRUE; |
||||
} |
||||
|
||||
/**
|
||||
* @internal |
||||
* @brief Shut down the share_common mutexs. |
||||
* |
||||
* This function shuts down the mutexs in the share_common module. |
||||
* It is called by eina_thread_shutdown(). |
||||
* |
||||
* @see eina_thread_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; |
||||
|
||||
DBG("str=%p (%.*s), slen=%u", str, slen, str ? str : "", slen); |
||||
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; |
||||
|
||||
SHARE_COMMON_LOCK_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); |
||||
SHARE_COMMON_UNLOCK_BIG(); |
||||
return s; |
||||
} |
||||
|
||||
EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, SHARE_COMMON_UNLOCK_BIG(), NULL); |
||||
|
||||
el = _eina_share_common_head_find(ed, str, slen); |
||||
if (el) |
||||
{ |
||||
EINA_MAGIC_CHECK_SHARE_COMMON_NODE(el, share->node_magic, SHARE_COMMON_UNLOCK_BIG()); |
||||
el->references++; |
||||
SHARE_COMMON_UNLOCK_BIG(); |
||||
return el->str; |
||||
} |
||||
|
||||
el = _eina_share_common_node_alloc(slen, null_size); |
||||
if (!el) |
||||
{ |
||||
SHARE_COMMON_UNLOCK_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); |
||||
|
||||
SHARE_COMMON_UNLOCK_BIG(); |
||||
|
||||
return el->str; |
||||
} |
||||
|
||||
const char * |
||||
eina_share_common_ref(Eina_Share *share, const char *str) |
||||
{ |
||||
Eina_Share_Common_Node *node; |
||||
|
||||
DBG("str=%p (%s)", str, str ? str : ""); |
||||
|