Eina: Add Eina_UStringshare and Eina_Binshare.
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: 50533
This commit is contained in:
parent
270f765c91
commit
3675a5f02b
|
@ -14,3 +14,4 @@ Raphael Kubo da Costa <kubo@profusion.mobi>
|
|||
Gustavo Chaves <glima@profusion.mobi>
|
||||
Fabiano Fidêncio <fidencio@profusion.mobi>
|
||||
Brett Nash <nash@nash.id.au>
|
||||
Tom Hacohen <tom@stosb.com>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
* Raphael Kubo da Costa <kubo@profusion.mobi>
|
||||
* Tilman Sauerbeck <tilman@code-monkey.de>
|
||||
* Vincent "caro" Torri <vtorri at univ-evry dot fr>
|
||||
* Tom Hacohen <tom@stosb.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -135,7 +136,9 @@ extern "C" {
|
|||
#include "eina_error.h"
|
||||
#include "eina_log.h"
|
||||
#include "eina_array.h"
|
||||
#include "eina_binshare.h"
|
||||
#include "eina_stringshare.h"
|
||||
#include "eina_ustringshare.h"
|
||||
#include "eina_magic.h"
|
||||
#include "eina_counter.h"
|
||||
#include "eina_rbtree.h"
|
||||
|
|
|
@ -25,7 +25,10 @@ eina_counter.h \
|
|||
eina_inline_array.x \
|
||||
eina_magic.h \
|
||||
eina_stringshare.h \
|
||||
eina_binshare.h \
|
||||
eina_ustringshare.h \
|
||||
eina_inline_stringshare.x \
|
||||
eina_inline_ustringshare.x \
|
||||
eina_inline_list.x \
|
||||
eina_accessor.h \
|
||||
eina_convert.h \
|
||||
|
|
|
@ -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_ */
|
|
@ -19,6 +19,8 @@
|
|||
#ifndef EINA_STRINGSHARE_INLINE_H_
|
||||
#define EINA_STRINGSHARE_INLINE_H_
|
||||
|
||||
#include <string.h>
|
||||
#include "eina_stringshare.h"
|
||||
/**
|
||||
* @addtogroup Eina_Stringshare_Group Stringshare
|
||||
*
|
||||
|
|
|
@ -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_ */
|
|
@ -52,9 +52,11 @@
|
|||
#define EINA_LOG_COLOR_DEFAULT "\033[36m"
|
||||
|
||||
/* eina magic types */
|
||||
#define EINA_MAGIC_STRINGSHARE 0x98761234
|
||||
#define EINA_MAGIC_STRINGSHARE_NODE 0x98761235
|
||||
#define EINA_MAGIC_STRINGSHARE_HEAD 0x98761236
|
||||
#define EINA_MAGIC_SHARE 0x98761234
|
||||
#define EINA_MAGIC_SHARE_HEAD 0x98761235
|
||||
#define EINA_MAGIC_STRINGSHARE_NODE 0x98761254
|
||||
#define EINA_MAGIC_USTRINGSHARE_NODE 0x98761255
|
||||
#define EINA_MAGIC_BINSHARE_NODE 0x98761256
|
||||
|
||||
#define EINA_MAGIC_LIST 0x98761237
|
||||
#define EINA_MAGIC_LIST_ITERATOR 0x98761238
|
||||
|
@ -81,6 +83,7 @@
|
|||
#define EINA_MAGIC_MATRIXSPARSE_CELL_ACCESSOR 0x98761249
|
||||
|
||||
#define EINA_MAGIC_STRBUF 0x98761250
|
||||
#define EINA_MAGIC_USTRBUF 0x98761257
|
||||
|
||||
#define EINA_MAGIC_QUADTREE 0x98761251
|
||||
#define EINA_MAGIC_QUADTREE_ROOT 0x98761252
|
||||
|
@ -121,8 +124,8 @@
|
|||
} while(0);
|
||||
|
||||
#ifdef EFL_HAVE_THREADS
|
||||
void eina_stringshare_threads_init(void);
|
||||
void eina_stringshare_threads_shutdown(void);
|
||||
void eina_share_common_threads_init(void);
|
||||
void eina_share_common_threads_shutdown(void);
|
||||
void eina_log_threads_init(void);
|
||||
void eina_log_threads_shutdown(void);
|
||||
#endif
|
||||
|
|
|
@ -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_ */
|
|
@ -32,7 +32,10 @@ eina_fp.c \
|
|||
eina_rbtree.c \
|
||||
eina_benchmark.c \
|
||||
eina_rectangle.c \
|
||||
eina_share_common.c \
|
||||
eina_binshare.c \
|
||||
eina_stringshare.c \
|
||||
eina_ustringshare.c \
|
||||
eina_cpu.c \
|
||||
eina_tiler.c \
|
||||
eina_hamster.c \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#include "eina_log.h"
|
||||
#include "eina_hash.h"
|
||||
#include "eina_stringshare.h"
|
||||
#include "eina_ustringshare.h"
|
||||
#include "eina_list.h"
|
||||
#include "eina_matrixsparse.h"
|
||||
#include "eina_array.h"
|
||||
|
@ -110,6 +111,7 @@ S(module);
|
|||
S(mempool);
|
||||
S(list);
|
||||
S(stringshare);
|
||||
S(ustringshare);
|
||||
S(matrixsparse);
|
||||
S(convert);
|
||||
S(counter);
|
||||
|
@ -139,6 +141,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = {
|
|||
S(mempool),
|
||||
S(list),
|
||||
S(stringshare),
|
||||
S(ustringshare),
|
||||
S(matrixsparse),
|
||||
S(convert),
|
||||
S(counter),
|
||||
|
@ -288,13 +291,13 @@ eina_threads_init(void)
|
|||
++_eina_main_thread_count;
|
||||
ret = _eina_main_thread_count;
|
||||
|
||||
if(_eina_main_thread_count > 1)
|
||||
if(_eina_main_thread_count > 1)
|
||||
{
|
||||
UNLOCK();
|
||||
return ret;
|
||||
}
|
||||
|
||||
eina_stringshare_threads_init();
|
||||
eina_share_common_threads_init();
|
||||
eina_log_threads_init();
|
||||
_threads_activated = EINA_TRUE;
|
||||
|
||||
|
@ -332,7 +335,7 @@ eina_threads_shutdown(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
eina_stringshare_threads_shutdown();
|
||||
eina_share_common_threads_shutdown();
|
||||
eina_log_threads_shutdown();
|
||||
|
||||
_threads_activated = EINA_FALSE;
|
||||
|
|
|
@ -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 : "");
|
||||
if (!str) return NULL;
|
||||
|
||||
SHARE_COMMON_LOCK_BIG();
|
||||
node = _eina_share_common_node_from_str(str, share->node_magic);
|
||||
node->references++;
|
||||
DBG("str=%p (%s) refs=%u", str, str, node->references);
|
||||
|
||||
SHARE_COMMON_UNLOCK_BIG();
|
||||
|
||||
eina_share_common_population_add(share, node->length);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
eina_share_common_del(Eina_Share *share, const char *str, int slen)
|
||||
{
|
||||
Eina_Share_Common_Head *ed;
|
||||
Eina_Share_Common_Head **p_bucket;
|
||||
Eina_Share_Common_Node *node;
|
||||
int hash_num, hash;
|
||||
|
||||
DBG("str=%p (%s)", str, str ? str : "");
|
||||
if (!str) return;
|
||||
|
||||
eina_share_common_population_del(share, slen);
|
||||
|
||||
SHARE_COMMON_LOCK_BIG();
|
||||
|
||||
node = _eina_share_common_node_from_str(str, share->node_magic);
|
||||
if (node->references > 1)
|
||||
{
|
||||
node->references--;
|
||||
DBG("str=%p (%s) refs=%u", str, str, node->references);
|
||||
SHARE_COMMON_UNLOCK_BIG();
|
||||
return;
|
||||
}
|
||||
|
||||
DBG("str=%p (%s) refs=0, delete.", str, str);
|
||||
node->references = 0;
|
||||
slen = node->length;
|
||||
|
||||
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, SHARE_COMMON_UNLOCK_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);
|
||||
|
||||
SHARE_COMMON_UNLOCK_BIG();
|
||||
|
||||
return;
|
||||
|
||||
on_error:
|
||||
SHARE_COMMON_UNLOCK_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);
|
||||
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");
|
||||
|
||||
SHARE_COMMON_LOCK_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(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
|
||||
|
||||
SHARE_COMMON_UNLOCK_BIG();
|
||||
}
|
||||
|
||||
/**
|
||||
* @endcond
|
||||
*/
|
|
@ -0,0 +1,93 @@
|
|||
/* 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_SHARE_COMMON_H_
|
||||
#define EINA_SHARE_COMMON_H_
|
||||
|
||||
#include "eina_types.h"
|
||||
#include "eina_magic.h"
|
||||
|
||||
typedef struct _Eina_Share Eina_Share;
|
||||
|
||||
struct dumpinfo
|
||||
{
|
||||
int used, saved, dups, unique;
|
||||
};
|
||||
|
||||
Eina_Bool eina_share_common_init(Eina_Share **share, Eina_Magic node_magic, const char *node_magic_STR);
|
||||
Eina_Bool eina_share_common_shutdown(Eina_Share **share);
|
||||
const char *eina_share_common_add_length(Eina_Share *share, const char *str, unsigned int slen, unsigned int null_size) EINA_WARN_UNUSED_RESULT;
|
||||
const char *eina_share_common_ref(Eina_Share *share, const char *str);
|
||||
void eina_share_common_del(Eina_Share *share, const char *str, int slen);
|
||||
int eina_share_common_length(Eina_Share *share, const char *str) EINA_CONST EINA_WARN_UNUSED_RESULT;
|
||||
void eina_share_common_dump(Eina_Share *share, void (* additional_dump)(struct dumpinfo *), int used);
|
||||
|
||||
|
||||
/* Population functions */
|
||||
void eina_share_common_population_add(Eina_Share *share, int slen);
|
||||
void eina_share_common_population_del(Eina_Share *share, int slen);
|
||||
|
||||
/* Share logging */
|
||||
#ifdef CRITICAL
|
||||
#undef CRITICAL
|
||||
#endif
|
||||
#define CRITICAL(...) EINA_LOG_DOM_CRIT(_eina_share_common_log_dom, __VA_ARGS__)
|
||||
|
||||
#ifdef ERR
|
||||
#undef ERR
|
||||
#endif
|
||||
#define ERR(...) EINA_LOG_DOM_ERR(_eina_share_common_log_dom, __VA_ARGS__)
|
||||
|
||||
#ifdef DBG
|
||||
#undef DBG
|
||||
#endif
|
||||
#define DBG(...) EINA_LOG_DOM_DBG(_eina_share_common_log_dom, __VA_ARGS__)
|
||||
extern int _eina_share_common_log_dom;
|
||||
#endif /* EINA_STRINGSHARE_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* 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_ustringshare_page UStringshare Tutorial
|
||||
*
|
||||
* 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_USTRINGSHARE_NODE_STR[] = "Eina UStringshare 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()
|
||||
*/
|
||||
Eina_Bool
|
||||
eina_ustringshare_init(void)
|
||||
{
|
||||
return eina_share_common_init(&share, EINA_MAGIC_USTRINGSHARE_NODE, EINA_MAGIC_USTRINGSHARE_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()
|
||||
*/
|
||||
Eina_Bool
|
||||
eina_ustringshare_shutdown(void)
|
||||
{
|
||||
Eina_Bool ret;
|
||||
ret = eina_share_common_shutdown(&share);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*============================================================================*
|
||||
* API *
|
||||
*============================================================================*/
|
||||
/**
|
||||
* @addtogroup Eina_UStringshare_Group Unicode Stringshare
|
||||
*
|
||||
* 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_ustringshare_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_ustringshare_del(const Eina_Unicode *str)
|
||||
{
|
||||
int slen;
|
||||
if (!str)
|
||||
return;
|
||||
slen = eina_unicode_strlen(str);
|
||||
slen = (int) (slen * sizeof(Eina_Unicode));
|
||||
eina_share_common_del(share,(const char *) str, slen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve an instance of a string for use in a program.
|
||||
*
|
||||
* @param str The string to retrieve an instance of.
|
||||
* @param slen The string size (<= strlen(str)).
|
||||
* @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_ustringshare_add()
|
||||
*/
|
||||
EAPI const Eina_Unicode *
|
||||
eina_ustringshare_add_length(const Eina_Unicode *str, unsigned int slen)
|
||||
{
|
||||
return (const Eina_Unicode *) eina_share_common_add_length(share,(const char *) str, slen * sizeof(Eina_Unicode), sizeof(Eina_Unicode));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve an instance of a string for use in a program.
|
||||
*
|
||||
* @param str The NULL terminated string to retrieve an instance of.
|
||||
* @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.
|
||||
*
|
||||
* The string @p str must be NULL terminated ('@\0') and its full
|
||||
* length will be used. To use part of the string or non-null
|
||||
* terminated, use eina_stringshare_add_length() instead.
|
||||
*
|
||||
* @see eina_ustringshare_add_length()
|
||||
*/
|
||||
EAPI const Eina_Unicode *
|
||||
eina_ustringshare_add(const Eina_Unicode *str)
|
||||
{
|
||||
int slen = (str) ? (int) eina_unicode_strlen(str) : -1;
|
||||
return eina_ustringshare_add_length(str, slen);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_ustringshare_add().
|
||||
*
|
||||
* There is no unref since this is the work of eina_ustringshare_del().
|
||||
*/
|
||||
EAPI const Eina_Unicode *
|
||||
eina_ustringshare_ref(const Eina_Unicode *str)
|
||||
{
|
||||
if (!str)
|
||||
{
|
||||
return (Eina_Unicode *) eina_share_common_ref(share, (const char *) str);
|
||||
}
|
||||
return (const Eina_Unicode *) 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_ustringshare_strlen(const Eina_Unicode *str)
|
||||
{
|
||||
int len = eina_share_common_length(share, (const char *) str);
|
||||
len = (len > 0) ? len / (int) sizeof(Eina_Unicode) : -1;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_ustringshare_dump(void)
|
||||
{
|
||||
eina_share_common_dump(share, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
Loading…
Reference in New Issue