Enlightenment CVS committal Author : moom Project : e17 Module : libs/etk
Dir : e17/libs/etk/src/lib Modified Files: etk_string.c etk_string.h Log Message: * [Etk_String] Make it faster when manipulating big texts. It also does less memory allocations now. * [Etk_String] Add property_set/get() functions * [Etk_String] Fix the documentation =================================================================== RCS file: /cvs/e/e17/libs/etk/src/lib/etk_string.c,v retrieving revision 1.19 retrieving revision 1.20 diff -u -3 -r1.19 -r1.20 --- etk_string.c 28 Sep 2007 19:47:51 -0000 1.19 +++ etk_string.c 31 Oct 2007 18:46:16 -0000 1.20 @@ -16,18 +16,29 @@ * @{ */ -#define ETK_STRING_BLOCK_SIZE 128 -#define ETK_STRING_SIZE_TO_ALLOC(length) \ - (((length) + (ETK_STRING_BLOCK_SIZE - 1)) / ETK_STRING_BLOCK_SIZE) * ETK_STRING_BLOCK_SIZE +#define BLOCK_SIZE 128 +#define SIZE_TO_ALLOC(length) \ + (((length) + (BLOCK_SIZE - 1)) / BLOCK_SIZE) * BLOCK_SIZE enum _Etk_String_Property_Id { ETK_STRING_STRING_PROPERTY }; -static void _etk_string_constructor(Etk_String *string); -static void _etk_string_destructor(Etk_String *string); +static void _etk_string_constructor(Etk_String *string); +static void _etk_string_destructor(Etk_String *string); +static void _etk_string_property_set(Etk_Object *object, int property_id, Etk_Property_Value *value); +static void _etk_string_property_get(Etk_Object *object, int property_id, Etk_Property_Value *value); static char *_etk_string_vprintf(const char *format, va_list args); +static int _etk_string_strlen_max(const char *string, int max_len); + +static char *_empty_string = ""; + +/************************** + * + * Implementation + * + **************************/ /** * @internal @@ -41,9 +52,12 @@ if (!string_type) { string_type = etk_type_new("Etk_String", ETK_OBJECT_TYPE, sizeof(Etk_String), - ETK_CONSTRUCTOR(_etk_string_constructor), ETK_DESTRUCTOR(_etk_string_destructor), NULL); + ETK_CONSTRUCTOR(_etk_string_constructor), ETK_DESTRUCTOR(_etk_string_destructor), NULL); etk_type_property_add(string_type, "string", ETK_STRING_STRING_PROPERTY, - ETK_PROPERTY_STRING, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_string(NULL)); + ETK_PROPERTY_STRING, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_string(NULL)); + + string_type->property_set = _etk_string_property_set; + string_type->property_get = _etk_string_property_get; } return string_type; @@ -51,61 +65,69 @@ /** * @brief Creates a new string - * @param value the default value of the string. Can be NULL + * @param value the default value of the string. It can be NULL * @return Returns the new string */ Etk_String *etk_string_new(const char *value) { - return etk_string_set(ETK_STRING(etk_object_new(ETK_STRING_TYPE, NULL)), value); + Etk_String *string; + + string = ETK_STRING(etk_object_new(ETK_STRING_TYPE, NULL)); + return etk_string_set(string, value); } /** * @brief Creates a new string, with a specific size. - * @param value the default value of the string. Can be NULL - * @param size If @a size is lower than the length of @a value, the string will be truncated. @n - * Otherwise, extra memory will be allocated (useful if you planned to insert text often - * and want to avoid too many reallocations) + * @param value the default value of the string. It can be NULL + * @param size If @a size is lower than the length of @a value, the value will be truncated. + * Otherwise, if @a size is greater than the length of @a value, extra memory will be allocated. + * It may be useful if you plan to often insert text and want to avoid too many reallocations. * @return Returns the new string */ Etk_String *etk_string_new_sized(const char *value, int size) { - return etk_string_set_sized(ETK_STRING(etk_object_new(ETK_STRING_TYPE, NULL)), value, size); + Etk_String *string; + + string = ETK_STRING(etk_object_new(ETK_STRING_TYPE, NULL)); + return etk_string_set_sized(string, value, size); } /** - * @brief Creates a new string, and sets its default value from the format and the arguments - * @param format the format to set to the string. It uses the same arguments than printf() + * @brief Creates a new string, and sets its default value from the given format and arguments + * @param format the format to set to the string. It uses the same arguments as printf() * @param ... the arguments corresponding to the format * @return Returns the new string */ Etk_String *etk_string_new_printf(const char *format, ...) { - Etk_String *new_string; + Etk_String *string; va_list args; va_start(args, format); - new_string = etk_string_set_vprintf(ETK_STRING(etk_object_new(ETK_STRING_TYPE, NULL)), format, args); + string = ETK_STRING(etk_object_new(ETK_STRING_TYPE, NULL)); + string = etk_string_set_vprintf(string, format, args); va_end(args); - return new_string; + return string; } /** - * @brief Creates a new string, and sets its default value from the format and the arguments - * @param format the format to set to the string. It uses the same arguments than printf() + * @brief Creates a new string, and sets its default value from the given format and arguments + * @param format the format to set to the string. It uses the same arguments as printf() * @param args the arguments corresponding to the format * @return Returns the new string */ Etk_String *etk_string_new_vprintf(const char *format, va_list args) { - Etk_String *new_string; + Etk_String *string; va_list args2; va_copy(args2, args); - new_string = etk_string_set_vprintf(ETK_STRING(etk_object_new(ETK_STRING_TYPE, NULL)), format, args2); + string = ETK_STRING(etk_object_new(ETK_STRING_TYPE, NULL)); + string = etk_string_set_vprintf(string, format, args2); va_end(args2); - return new_string; + return string; } /** @@ -122,15 +144,15 @@ } /** - * @brief Gets the string as an array of char + * @brief Gets the string as an array of chars * @param string a string - * @param Returns the string as an array of char (a pointer on the first character) + * @param Returns the string as an array of chars (i.e a pointer on the first character) */ const char *etk_string_get(Etk_String *string) { if (!string) return NULL; - return string->string; + return string->string ? string->string : _empty_string; } /** @@ -148,28 +170,30 @@ /** * @brief Truncates the string * @param string a string - * @param length the new length of the string. If @a length is greater than the current length of the string, the function does nothing + * @param length the new length of the string. If @a length is greater than + * the current length of the string, the function does nothing * @return Returns the truncated string */ Etk_String *etk_string_truncate(Etk_String *string, int length) { - if (!string) + if (!string || length < 0) return NULL; if (length < string->length) { - string->string[length] = 0; + string->string[length] = '\0'; string->length = length; etk_object_notify(ETK_OBJECT(string), "string"); } + return string; } /** - * @brief Removes from the string a segment of size "size" from the position "pos" + * @brief Removes from the string a segment of @a size chars from the position @a pos * @param string a string - * @param pos the position where to start the deletion - * @param size the size of the segment of text to remove + * @param pos the position where to start the deletion (starting from 0) + * @param size the number of chars to remove * @return Returns the string */ Etk_String *etk_string_delete(Etk_String *string, int pos, int size) @@ -189,9 +213,10 @@ } /** - * @brief Clears the string: all the allocated memory will be freed, and the length of the string will be 0 + * @brief Clears the string: all the allocated memory will be freed, + * and the length of the string will be set to 0 * @param string the string to clear - * @return Returns the string + * @return Returns the cleared string */ Etk_String *etk_string_clear(Etk_String *string) { @@ -199,7 +224,7 @@ return NULL; free(string->string); - string->string = strdup(""); + string->string = NULL; string->length = 0; string->allocated_length = 0; @@ -221,8 +246,9 @@ * @brief Sets the value of a string, with a specific size. * @param string a string. If @a string is NULL, a new string is created * @param value the value to assign to the string - * @param size If @a size is lower than the length of @a value, the string will be truncated. @n - * Otherwise, extra memory will be allocated (useful if you planned to insert text often and want to avoid too many reallocations) + * @param size If @a size is lower than the length of @a value, the value will be truncated. + * Otherwise, if @a size is greater than the length of @a value, extra memory will be allocated. + * It may be useful if you plan to often insert text and want to avoid too many reallocations. * @return Returns the string */ Etk_String *etk_string_set_sized(Etk_String *string, const char *value, int size) @@ -230,26 +256,20 @@ if (!string) return etk_string_new_sized(value, size); - if (!value || *value == 0 || size <= 0) - { - *string->string = 0; - string->length = 0; - } + if (!value || value[0] == '\0' || size <= 0) + return etk_string_clear(string); else { - int length; - if (size > string->allocated_length) { free(string->string); - string->string = malloc(ETK_STRING_SIZE_TO_ALLOC(size) + 1); - string->allocated_length = ETK_STRING_SIZE_TO_ALLOC(size); + string->string = malloc(SIZE_TO_ALLOC(size) + 1); + string->allocated_length = SIZE_TO_ALLOC(size); } - length = strlen(value); - string->length = ETK_MIN(length, size); + string->length = _etk_string_strlen_max(value, size); strncpy(string->string, value, string->length); - string->string[string->length] = 0; + string->string[string->length] = '\0'; } etk_object_notify(ETK_OBJECT(string), "string"); @@ -257,22 +277,21 @@ } /** - * @brief Sets the value of the string from the format and the arguments + * @brief Sets the value of the string from the given format and arguments * @param string a string. If @a string is NULL, a new string is created - * @param format the format to set to the string. It uses the same arguments than printf() + * @param format the format to set to the string. It uses the same arguments as printf() * @param ... the arguments corresponding to the format * @return Returns the string */ Etk_String *etk_string_set_printf(Etk_String *string, const char *format, ...) { va_list args; - Etk_String *result; va_start(args, format); - result = etk_string_set_vprintf(string, format, args); + string = etk_string_set_vprintf(string, format, args); va_end(args); - return result; + return string; } /** @@ -286,15 +305,14 @@ { va_list args2; char *text; - Etk_String *result; va_copy(args2, args); text = _etk_string_vprintf(format, args2); - result = etk_string_set(string, text); + string = etk_string_set(string, text); free(text); va_end(args2); - return result; + return string; } /** @@ -309,7 +327,7 @@ } /** - * @brief Prepends a text with a specific length to a string + * @brief Prepends a text with a specific length to a string * @param string a string. If @a string is NULL, a new string is created * @param text the text to prepend to the string * @param length the length of the text to prepend @@ -332,41 +350,41 @@ } /** - * @brief Prepends a text to a string from the format and the arguments + * @brief Prepends a text to the string, from the given format and arguments * @param string a string. If @a string is NULL, a new string is created - * @param format the format to prepend to the string. It uses the same arguments than printf() + * @param format the format of the text to prepend to the string. + * It uses the same arguments than printf() * @param ... the arguments corresponding to the format * @return Returns the string */ Etk_String *etk_string_prepend_printf(Etk_String *string, const char *format, ...) { va_list args; - Etk_String *result; va_start(args, format); - result = etk_string_prepend_vprintf(string, format, args); + string = etk_string_prepend_vprintf(string, format, args); va_end(args); - return result; + return string; } /** - * @brief Prepends a text to a string from the format and the arguments + * @brief Prepends a text to the string, from the given format and arguments * @param string a string. If @a string is NULL, a new string is created - * @param format the format to prepend to the string. It uses the same arguments than printf() + * @param format the format of the text to prepend to the string. + * It uses the same arguments than printf() * @param args the arguments corresponding to the format * @return Returns the string */ Etk_String *etk_string_prepend_vprintf(Etk_String *string, const char *format, va_list args) { va_list args2; - Etk_String *result; va_copy(args2, args); - result = etk_string_insert_vprintf(string, 0, format, args2); + string = etk_string_insert_vprintf(string, 0, format, args2); va_end(args2); - return result; + return string; } /** @@ -381,7 +399,7 @@ } /** - * @brief Appends a text with a specific length to a string + * @brief Appends a text with a specific length to a string * @param string a string. If @a string is NULL, a new string is created * @param text the text to append to the string * @param length the length of the text to append @@ -404,47 +422,47 @@ } /** - * @brief Appends a text to a string from the format and the arguments + * @brief Appends a text to the string, from the given format and arguments * @param string a string. If @a string is NULL, a new string is created - * @param format the format to append to the string. It uses the same arguments than printf() + * @param format the format of the text to append to the string. + * It uses the same arguments than printf() * @param ... the arguments corresponding to the format * @return Returns the string */ Etk_String *etk_string_append_printf(Etk_String *string, const char *format, ...) { va_list args; - Etk_String *result; va_start(args, format); - result = etk_string_append_vprintf(string, format, args); + string = etk_string_append_vprintf(string, format, args); va_end(args); - return result; + return string; } /** - * @brief Appends a text to a string from the format and the arguments + * @brief Appends a text to the string, from the given format and arguments * @param string a string. If @a string is NULL, a new string is created - * @param format the format to append to the string. It uses the same arguments than printf() + * @param format the format of the text to append to the string. + * It uses the same arguments than printf() * @param args the arguments corresponding to the format * @return Returns the string */ Etk_String *etk_string_append_vprintf(Etk_String *string, const char *format, va_list args) { va_list args2; - Etk_String *result; va_copy(args2, args); - result = etk_string_insert_vprintf(string, string->length, format, args2); + string = etk_string_insert_vprintf(string, string->length, format, args2); va_end(args2); - return result; + return string; } /** - * @brief Inserts a text into a string + * @brief Inserts a text into a string, at a given position * @param string a string. If @a string is NULL, a new string is created - * @param pos the position where to insert the text + * @param pos the position where to insert the text (starting from 0) * @param text the text to insert into the string * @return Returns the string */ @@ -454,41 +472,41 @@ } /** - * @brief Inserts a text with a specific length into a string + * @brief Inserts a text with a specific length into a string, at a given position * @param string a string. If @a string is NULL, a new string is created - * @param pos the position where to insert the text + * @param pos the position where to insert the text (starting from 0) * @param text the text to insert into the string - * @param length the length of the text to insert + * @param length the maximum length of the text to insert * @return Returns the string */ Etk_String *etk_string_insert_sized(Etk_String *string, int pos, const char *text, int length) { if (!string) return etk_string_new_sized(text, length); - if (!text || *text == 0 || length <= 0) + if (!text || text[0] == '\0' || length <= 0) return string; pos = ETK_CLAMP(pos, 0, string->length); - length = ETK_MIN(length, strlen(text)); + length = _etk_string_strlen_max(text, length); if (string->length + length > string->allocated_length) { - string->string = realloc(string->string, ETK_STRING_SIZE_TO_ALLOC(string->length + length) + 1); - string->allocated_length = ETK_STRING_SIZE_TO_ALLOC(string->length + length); + string->string = realloc(string->string, SIZE_TO_ALLOC(string->length + length) + 1); + string->allocated_length = SIZE_TO_ALLOC(string->length + length); } memmove(&string->string[pos + length], &string->string[pos], string->length - pos); strncpy(&string->string[pos], text, length); string->length += length; - string->string[string->length] = 0; + string->string[string->length] = '\0'; etk_object_notify(ETK_OBJECT(string), "string"); return string; } /** - * @brief Inserts a character into a string + * @brief Inserts a character into a string, at a given position * @param string a string. If @a string is NULL, a new string is created - * @param pos the positon where to insert the char + * @param pos the position where to insert the char * @param c the character to insert into the string * @return Returns the string */ @@ -498,30 +516,30 @@ if (!string) return etk_string_insert_char(etk_string_new(NULL), pos, c); - if (c == 0) + if (c == '\0') return etk_string_truncate(string, pos); pos = ETK_CLAMP(pos, 0, string->length); if (string->length + 1 > string->allocated_length) { - string->string = realloc(string->string, ETK_STRING_SIZE_TO_ALLOC(string->length + 1) + 1); - string->allocated_length = ETK_STRING_SIZE_TO_ALLOC(string->length + 1); + string->string = realloc(string->string, SIZE_TO_ALLOC(string->length + 1) + 1); + string->allocated_length = SIZE_TO_ALLOC(string->length + 1); } for (i = string->length - 1; i >= pos; i--) string->string[i + 1] = string->string[i]; string->string[pos] = c; string->length++; - string->string[string->length] = 0; + string->string[string->length] = '\0'; etk_object_notify(ETK_OBJECT(string), "string"); return string; } /** - * @brief Inserts a text into a string from the format and the arguments + * @brief Inserts a text into a string, from the given format and arguments, at a given position * @param string a string. If @a string is NULL, a new string is created - * @param pos the positon where to insert the char + * @param pos the position where to insert the text * @param format the format to insert into the string. It uses the same arguments than printf() * @param ... the arguments corresponding to the format * @return Returns the string @@ -529,19 +547,18 @@ Etk_String *etk_string_insert_printf(Etk_String *string, int pos, const char *format, ...) { va_list args; - Etk_String *result; va_start(args, format); - result = etk_string_insert_vprintf(string, pos, format, args); + string = etk_string_insert_vprintf(string, pos, format, args); va_end(args); - return result; + return string; } /** - * @brief Inserts a text into a string from the format and the arguments + * @brief Inserts a text into a string, from the given format and arguments, at a given position * @param string a string. If @a string is NULL, a new string is created - * @param pos the positon where to insert the char + * @param pos the position where to insert the text * @param format the format to insert into the string. It uses the same arguments than printf() * @param args the arguments corresponding to the format * @return Returns the string @@ -549,16 +566,15 @@ Etk_String *etk_string_insert_vprintf(Etk_String *string, int pos, const char *format, va_list args) { va_list args2; - char *text_to_append; - Etk_String *result; + char *text; va_copy(args2, args); - text_to_append = _etk_string_vprintf(format, args2); - result = etk_string_insert(string, pos, text_to_append); - free(text_to_append); + text = _etk_string_vprintf(format, args2); + string = etk_string_insert(string, pos, text); + free(text); va_end(args2); - return result; + return string; } /************************** @@ -573,7 +589,7 @@ if (!string) return; - string->string = strdup(""); + string->string = NULL; string->length = 0; string->allocated_length = 0; } @@ -586,13 +602,49 @@ free(string->string); } +/* Sets the property whose id is "property_id" to the value "value" */ +static void _etk_string_property_set(Etk_Object *object, int property_id, Etk_Property_Value *value) +{ + Etk_String *string; + + if (!(string = ETK_STRING(object)) || !value) + return; + + switch (property_id) + { + case ETK_STRING_STRING_PROPERTY: + etk_string_set(string, etk_property_value_string_get(value)); + break; + default: + break; + } +} + +/* Gets the value of the property whose id is "property_id" */ +static void _etk_string_property_get(Etk_Object *object, int property_id, Etk_Property_Value *value) +{ + Etk_String *string; + + if (!(string = ETK_STRING(object)) || !value) + return; + + switch (property_id) + { + case ETK_STRING_STRING_PROPERTY: + etk_property_value_string_set(value, string->string); + break; + default: + break; + } +} + /************************** * * Private functions * **************************/ -/* Creates a new string (char *) from the format and the args, and returns it. +/* Creates a new string (char *) from the given format and args, and returns it. * The returned string will have to be freed */ static char *_etk_string_vprintf(const char *format, va_list args) { @@ -615,4 +667,39 @@ return text; } +/* Calculates the length of the given string. + * The returned length can not be greater than "max_len" */ +static int _etk_string_strlen_max(const char *string, int max_len) +{ + int i; + + if (!string) + return 0; + + for (i = 0; i < max_len && string[i] != '\0'; i++); + return i; +} + /** @} */ + +/************************** + * + * Documentation + * + **************************/ + +/** + * @addtogroup Etk_String + * + * TODOC + * + * \par Object Hierarchy: + * - Etk_Object + * - Etk_String + * + * \par Properties: + * @prop_name "string": the value of the string + * @prop_type String (char *) + * @prop_rw + * @prop_val NULL + */ =================================================================== RCS file: /cvs/e/e17/libs/etk/src/lib/etk_string.h,v retrieving revision 1.9 retrieving revision 1.10 diff -u -3 -r1.9 -r1.10 --- etk_string.h 19 Sep 2007 20:16:26 -0000 1.9 +++ etk_string.h 31 Oct 2007 18:46:16 -0000 1.10 @@ -11,21 +11,25 @@ extern "C" { #endif +/* TODO: Etk_Object is a little too heavy for a string... + maybe we could use Etk_Base instead? */ + /** * @defgroup Etk_String Etk_String + * @brief An object that offers convenient methods to manipulate a string * @{ */ -/** @brief Gets the type of a string */ +/** Gets the type of a string */ #define ETK_STRING_TYPE (etk_string_type_get()) -/** @brief Casts the object to an Etk_String */ +/** Casts the object to an Etk_String */ #define ETK_STRING(obj) (ETK_OBJECT_CAST((obj), ETK_STRING_TYPE, Etk_String)) -/** @brief Checks if the object is an Etk_Text_Buffer */ +/** Checks if the object is an Etk_String */ #define ETK_IS_STRING(obj) (ETK_OBJECT_CHECK_TYPE((obj), ETK_STRING_TYPE)) /** - * @struct Etk_String - * @brief An Etk_String is an easy way to manipulate a string + * @brief @widget Etk_String is an object that offers convenient methods to manipulate a string + * @structinfo */ struct Etk_String { ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs