pnoltes commented on code in PR #470:
URL: https://github.com/apache/celix/pull/470#discussion_r1398214396
##########
libs/utils/src/properties.c:
##########
@@ -191,324 +481,449 @@ static void parseLine(const char* line,
celix_properties_t *props) {
}
if (!isComment) {
- //printf("putting 'key'/'value' '%s'/'%s' in properties\n",
utils_stringTrim(key), utils_stringTrim(value));
+ // printf("putting 'key'/'value' '%s'/'%s' in properties\n",
utils_stringTrim(key), utils_stringTrim(value));
celix_properties_set(props, celix_utils_trimInPlace(key),
celix_utils_trimInPlace(value));
}
- if(key) {
+ if (key) {
free(key);
- }
- if(value) {
free(value);
}
-
}
+celix_properties_t* celix_properties_loadWithStream(FILE* file) {
+ if (file == NULL) {
+ return NULL;
+ }
-/**********************************************************************************************************************
-
**********************************************************************************************************************
- * Updated API
-
**********************************************************************************************************************
-
**********************************************************************************************************************/
+ celix_autoptr(celix_properties_t) props = celix_properties_create();
+ if (!props) {
+ celix_err_push("Failed to create properties");
+ return NULL;
+ }
+ int rc = fseek(file, 0, SEEK_END);
+ if (rc != 0) {
+ celix_err_pushf("Cannot seek to end of file. Got error %i", errno);
+ return NULL;
+ }
+ size_t fileSize = ftell(file);
+ rc = fseek(file, 0, SEEK_SET);
+ if (rc != 0) {
+ celix_err_pushf("Cannot seek to start of file. Got error %i", errno);
+ return NULL;
+ }
+ char* fileBuffer = malloc(fileSize + 1);
+ if (fileBuffer == NULL) {
+ celix_err_pushf("Cannot allocate memory for file buffer. Got error
%i", errno);
+ return NULL;
+ }
-celix_properties_t* celix_properties_create(void) {
- return hashMap_create(utils_stringHash, utils_stringHash,
utils_stringEquals, utils_stringEquals);
-}
+ size_t rs = fread(fileBuffer, sizeof(char), fileSize, file);
+ if (rs < fileSize) {
+ fprintf(stderr, "fread read only %zu bytes out of %zu\n", rs,
fileSize);
+ }
+ fileBuffer[fileSize] = '\0'; // ensure a '\0' at the end of the fileBuffer
-void celix_properties_destroy(celix_properties_t *properties) {
- if (properties != NULL) {
- hash_map_iterator_pt iter = hashMapIterator_create(properties);
- while (hashMapIterator_hasNext(iter)) {
- hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
- hashMapEntry_clear(entry, true, true);
- }
- hashMapIterator_destroy(iter);
- hashMap_destroy(properties, false, false);
+ char* savePtr = NULL;
+ char* line = strtok_r(fileBuffer, "\n", &savePtr);
+ while (line != NULL) {
+ celix_properties_parseLine(line, props);
+ line = strtok_r(NULL, "\n", &savePtr);
}
+ free(fileBuffer);
+
+ return celix_steal_ptr(props);
}
-celix_properties_t* celix_properties_load(const char *filename) {
- FILE *file = fopen(filename, "r");
- if (file == NULL) {
+celix_properties_t* celix_properties_loadFromString(const char* input) {
+ celix_autoptr(celix_properties_t) props = celix_properties_create();
+ celix_autofree char* in = celix_utils_strdup(input);
+ if (!props || !in) {
+ celix_err_push("Failed to create properties or duplicate input
string");
return NULL;
}
- celix_properties_t *props = celix_properties_loadWithStream(file);
- fclose(file);
- return props;
-}
-celix_properties_t* celix_properties_loadWithStream(FILE *file) {
- celix_properties_t *props = NULL;
-
- if (file != NULL ) {
- char *saveptr;
- char *filebuffer = NULL;
- char *line = NULL;
- ssize_t file_size = 0;
-
- props = celix_properties_create();
- fseek(file, 0, SEEK_END);
- file_size = ftell(file);
- fseek(file, 0, SEEK_SET);
+ char* line = NULL;
+ char* saveLinePointer = NULL;
+ line = strtok_r(in, "\n", &saveLinePointer);
+ while (line != NULL) {
+ celix_properties_parseLine(line, props);
+ line = strtok_r(NULL, "\n", &saveLinePointer);
+ }
+ return celix_steal_ptr(props);
+}
- if (file_size > 0) {
- filebuffer = calloc(file_size + 1, sizeof(char));
- if (filebuffer) {
- size_t rs = fread(filebuffer, sizeof(char), file_size, file);
- if (rs != file_size) {
- fprintf(stderr,"fread read only %lu bytes out of %lu\n",
(long unsigned int) rs, (long unsigned int) file_size);
- }
- filebuffer[file_size]='\0';
- line = strtok_r(filebuffer, "\n", &saveptr);
- while (line != NULL) {
- parseLine(line, props);
- line = strtok_r(NULL, "\n", &saveptr);
- }
- free(filebuffer);
+/**
+ * @brief Store properties string to file and escape the characters '#', '!',
'=' and ':' if encountered.
+ */
+static int celix_properties_storeEscapedString(FILE* file, const char* str) {
+ int rc = 0;
+ for (int i = 0; i < strlen(str); i += 1) {
+ if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') {
+ rc = fputc('\\', file);
+ if (rc == EOF) {
+ break;
}
}
+ rc = fputc(str[i], file);
}
-
- return props;
+ return rc;
}
-celix_properties_t* celix_properties_loadFromString(const char *input) {
- celix_properties_t *props = celix_properties_create();
+celix_status_t celix_properties_store(celix_properties_t* properties, const
char* filename, const char* header) {
+ FILE* file = fopen(filename, "w+");
- char *in = strdup(input);
- char *line = NULL;
- char *saveLinePointer = NULL;
+ if (file == NULL) {
+ celix_err_pushf("Cannot open file '%s'", filename);
+ return CELIX_FILE_IO_EXCEPTION;
+ }
+
+ int rc = 0;
- bool firstTime = true;
- do {
- if (firstTime){
- line = strtok_r(in, "\n", &saveLinePointer);
- firstTime = false;
- }else {
- line = strtok_r(NULL, "\n", &saveLinePointer);
+ if (header && strstr("\n", header)) {
+ celix_err_push("Header cannot contain newlines. Ignoring header.");
+ } else if (header) {
+ rc = fputc('#', file);
+ if (rc != 0) {
+ rc = fputs(header, file);
+ }
+ if (rc != 0) {
+ rc = fputc('\n', file);
}
+ }
- if (line == NULL){
- break;
+ CELIX_PROPERTIES_ITERATE(properties, iter) {
+ const char* val = iter.entry.value;
+ if (rc != EOF) {
+ rc = celix_properties_storeEscapedString(file, iter.key);
+ }
+ if (rc != EOF) {
+ rc = fputc('=', file);
+ }
+ if (rc != EOF) {
+ rc = celix_properties_storeEscapedString(file, val);
+ }
+ if (rc != EOF) {
+ rc = fputc('\n', file);
}
+ }
+ if (rc != EOF) {
+ rc = fclose(file);
+ } else {
+ fclose(file);
+ }
+ if (rc == EOF) {
+ celix_err_push("Failed to write properties to file");
+ return CELIX_FILE_IO_EXCEPTION;
+ }
+ return CELIX_SUCCESS;
+}
- parseLine(line, props);
- } while(line != NULL);
+celix_properties_t* celix_properties_copy(const celix_properties_t*
properties) {
+ celix_properties_t* copy = celix_properties_create();
- free(in);
+ if (!copy) {
+ celix_err_push("Failed to create properties copy");
+ return NULL;
+ }
- return props;
+ if (!properties) {
+ return copy;
+ }
+
+ CELIX_PROPERTIES_ITERATE(properties, iter) {
+ celix_status_t status;
+ if (iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_STRING) {
+ status = celix_properties_set(copy, iter.key, iter.entry.value);
+ } else if (iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_LONG) {
+ status = celix_properties_setLong(copy, iter.key,
iter.entry.typed.longValue);
+ } else if (iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_DOUBLE)
{
+ status = celix_properties_setDouble(copy, iter.key,
iter.entry.typed.doubleValue);
+ } else if (iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_BOOL) {
+ status = celix_properties_setBool(copy, iter.key,
iter.entry.typed.boolValue);
+ } else /*version*/ {
+ assert(iter.entry.valueType ==
CELIX_PROPERTIES_VALUE_TYPE_VERSION);
+ status = celix_properties_setVersion(copy, iter.key,
iter.entry.typed.versionValue);
+ }
+ if (status != CELIX_SUCCESS) {
+ celix_err_pushf("Failed to copy property %s", iter.key);
+ celix_properties_destroy(copy);
+ return NULL;
+ }
+ }
+ return celix_steal_ptr(copy);
}
-void celix_properties_store(celix_properties_t *properties, const char
*filename, const char *header) {
- FILE *file = fopen (filename, "w+" );
- char *str;
+celix_properties_value_type_e celix_properties_getType(const
celix_properties_t* properties, const char* key) {
+ celix_properties_entry_t* entry = celix_stringHashMap_get(properties->map,
key);
+ return entry == NULL ? CELIX_PROPERTIES_VALUE_TYPE_UNSET :
entry->valueType;
+}
- if (file != NULL) {
- if (hashMap_size(properties) > 0) {
- hash_map_iterator_pt iterator = hashMapIterator_create(properties);
- while (hashMapIterator_hasNext(iterator)) {
- hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
- str = hashMapEntry_getKey(entry);
- for (int i = 0; i < strlen(str); i += 1) {
- if (str[i] == '#' || str[i] == '!' || str[i] == '=' ||
str[i] == ':') {
- fputc('\\', file);
- }
- fputc(str[i], file);
- }
+const char* celix_properties_get(const celix_properties_t* properties, const
char* key, const char* defaultValue) {
+ celix_properties_entry_t* entry = celix_properties_getEntry(properties,
key);
+ if (entry != NULL) {
+ return entry->value;
+ }
+ return defaultValue;
+}
- fputc('=', file);
+celix_properties_entry_t* celix_properties_getEntry(const celix_properties_t*
properties, const char* key) {
+ celix_properties_entry_t* entry = NULL;
+ if (properties) {
+ entry = celix_stringHashMap_get(properties->map, key);
+ }
+ return entry;
+}
- str = hashMapEntry_getValue(entry);
- for (int i = 0; i < strlen(str); i += 1) {
- if (str[i] == '#' || str[i] == '!' || str[i] == '=' ||
str[i] == ':') {
- fputc('\\', file);
- }
- fputc(str[i], file);
- }
+celix_status_t celix_properties_set(celix_properties_t* properties, const
char* key, const char* value) {
+ return celix_properties_createAndSetEntry(properties, key, &value, NULL,
NULL, NULL, NULL);
+}
- fputc('\n', file);
+celix_status_t celix_properties_setWithoutCopy(celix_properties_t* properties,
char* key, char* value) {
+ if (properties) {
+ if (!key || !value) {
+ celix_err_push("Failed to set (without copy) property. Key or
value is NULL.");
+ free(key);
+ free(value);
+ return CELIX_ILLEGAL_ARGUMENT;
+ }
+ celix_properties_entry_t* entry =
celix_properties_createEntryWithNoCopy(properties, value);
+ if (!entry) {
+ celix_err_push("Failed to create entry for property.");
+ free(key);
+ free(value);
+ return CELIX_ENOMEM;
+ }
- }
- hashMapIterator_destroy(iterator);
+ bool alreadyExist = celix_stringHashMap_hasKey(properties->map, key);
+ celix_status_t status = celix_stringHashMap_put(properties->map, key,
entry);
+ if (status != CELIX_SUCCESS) {
+ celix_err_pushf("Failed to put entry for key %s in map.", key);
+ free(key);
+ celix_properties_destroyEntry(properties, entry);
+ } else if (alreadyExist) {
+ free(key);
}
- fclose(file);
- } else {
- perror("File is null");
+ return status;
}
+ return CELIX_SUCCESS; // silently ignore NULL properties, key or value
+}
+
+celix_status_t
+celix_properties_setEntry(celix_properties_t* properties, const char* key,
const celix_properties_entry_t* entry) {
+ if (entry) {
+ switch (entry->valueType) {
+ case CELIX_PROPERTIES_VALUE_TYPE_LONG:
+ return celix_properties_setLong(properties, key,
entry->typed.longValue);
+ case CELIX_PROPERTIES_VALUE_TYPE_DOUBLE:
+ return celix_properties_setDouble(properties, key,
entry->typed.doubleValue);
+ case CELIX_PROPERTIES_VALUE_TYPE_BOOL:
+ return celix_properties_setBool(properties, key,
entry->typed.boolValue);
+ case CELIX_PROPERTIES_VALUE_TYPE_VERSION:
+ return celix_properties_setVersion(properties, key,
entry->typed.versionValue);
+ default: // STRING
+ return celix_properties_set(properties, key, entry->value);
Review Comment:
I agree, updated this to entry->typed.strValue and updated the code
documentation to indicate what is used in the entry for copying.
##########
libs/utils/src/celix_hash_map.c:
##########
@@ -19,64 +19,56 @@
#include "celix_string_hash_map.h"
#include "celix_long_hash_map.h"
-#include "celix_utils.h"
+#include "celix_hash_map_private.h"
+#include "celix_hash_map_internal.h"
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <assert.h>
#include <stdint.h>
-/**
- * Whether to use realloc - instead of calloc - to resize a hash map.
- *
- * With realloc the memory is increased and the
- * map entries are corrected.
- *
- * With alloc a new buckets array is allocated and
- * entries are moved into the new bucket array.
- * And the old buckets array is freed.
- *
- */
-#define CELIX_HASH_MAP_RESIZE_WITH_REALLOC
-
-static unsigned int DEFAULT_INITIAL_CAPACITY = 16;
-static double DEFAULT_LOAD_FACTOR = 0.75;
-static unsigned int MAXIMUM_CAPACITY = INT32_MAX/10;
+#include "celix_utils.h"
+#include "celix_err.h"
+#include "celix_stdlib_cleanup.h"
-typedef enum celix_hash_map_key_type {
- CELIX_HASH_MAP_STRING_KEY,
- CELIX_HASH_MAP_LONG_KEY
-} celix_hash_map_key_type_e;
+#define CELIX_HASHMAP_DEFAULT_INITIAL_CAPACITY 16
+#define CELIX_HASHMAP_DEFAULT_MAX_LOAD_FACTOR 5.0
+#define CELIX_HASHMAP_CAPACITY_INCREASE_FACTOR 2
+#define CELIX_HASHMAP_MAXIMUM_CAPACITY (INT32_MAX/10)
+#define CELIX_HASHMAP_MAXIMUM_INCREASE_VALUE (1024*10)
+#define CELIX_HASHMAP_HASH_PRIME 1610612741
-typedef union celix_hash_map_key {
+union celix_hash_map_key {
const char* strKey;
long longKey;
-} celix_hash_map_key_t;
+};
-typedef struct celix_hash_map_entry celix_hash_map_entry_t;
struct celix_hash_map_entry {
celix_hash_map_key_t key;
celix_hash_map_value_t value;
celix_hash_map_entry_t* next;
unsigned int hash;
};
-typedef struct celix_hash_map {
+struct celix_hash_map {
celix_hash_map_entry_t** buckets;
unsigned int bucketsSize; //nr of buckets
unsigned int size; //nr of total entries
- double loadFactor;
+ double maxLoadFactor;
celix_hash_map_key_type_e keyType;
- celix_hash_map_value_t emptyValue;
- unsigned int (*hashKeyFunction)(const celix_hash_map_key_t* key);
- bool (*equalsKeyFunction)(const celix_hash_map_key_t* key1, const
celix_hash_map_key_t* key2);
void (*simpleRemovedCallback)(void* value);
void* removedCallbackData;
- void (*removedStringKeyCallback)(void* data, const char* removedKey,
celix_hash_map_value_t removedValue);
- void (*removedLongKeyCallback)(void* data, long removedKey,
celix_hash_map_value_t removedValue);
+ void (*removedStringEntryCallback)(void* data, const char* removedKey,
celix_hash_map_value_t removedValue);
+ void (*removedStringKeyCallback)(void* data, char* key);
+ void (*removedLongEntryCallback)(void* data, long removedKey,
celix_hash_map_value_t removedValue);
bool storeKeysWeakly;
-} celix_hash_map_t;
+
+ //statistics
+ size_t modificationsCount;
+ size_t resizeCount;
+ size_t collisionsCount;
Review Comment:
removed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]