From a251bf5d6fa75d669b5394c349903c75329ef9aa Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Wed, 10 Dec 2014 18:27:36 +0300 Subject: [PATCH] Add array list structure. Change hash table to use array lists instead of linked lists. --- src/libintstructs/array-list.c | 137 +++++++++++++++++++++++++++++++++ src/libintstructs/array-list.h | 34 ++++++++ src/libintstructs/hash-table.c | 136 ++++++++++++++++++++++++++++++++ src/libintstructs/hash-table.h | 93 ++-------------------- 4 files changed, 314 insertions(+), 86 deletions(-) create mode 100644 src/libintstructs/array-list.c create mode 100644 src/libintstructs/array-list.h create mode 100644 src/libintstructs/hash-table.c diff --git a/src/libintstructs/array-list.c b/src/libintstructs/array-list.c new file mode 100644 index 000000000..bef44c54f --- /dev/null +++ b/src/libintstructs/array-list.c @@ -0,0 +1,137 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "array-list.h" +#include "mem-heap.h" +#include "jerry-libc.h" + +#define ARRAY_LIST_MAGIC 0x39 + +typedef struct +{ + uint8_t magic; + uint8_t element_size; + size_t len; + size_t size; +} +array_list_header; + +static array_list_header * +extract_header (array_list al) +{ + JERRY_ASSERT (al != null_list); + array_list_header *header = (array_list_header *) al; + JERRY_ASSERT (header->magic == ARRAY_LIST_MAGIC); + return header; +} + +static uint8_t * +data (array_list al) +{ + return (uint8_t *) al + sizeof (array_list_header); +} + +array_list +array_list_append (array_list al, void *element) +{ + array_list_header *h = extract_header (al); + if ((h->len + 1) * h->element_size + sizeof (array_list_header) > h->size) + { + size_t size = mem_heap_recommend_allocation_size (h->size + h->element_size); + array_list_header *temp = (array_list_header *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_SHORT_TERM); + __memset (temp, 0, size); + __memcpy (temp, h, h->size); + temp->size = size; + mem_heap_free_block ((uint8_t *) h); + h = temp; + al = (array_list) h; + } + __memcpy (data (al) + (h->len * h->element_size), element, h->element_size); + h->len++; + return al; +} + +void +array_list_drop_last (array_list al) +{ + array_list_header *h = extract_header (al); + JERRY_ASSERT (h->len > 0); + h->len--; +} + +void * +array_list_element (array_list al, size_t index) +{ + array_list_header *h = extract_header (al); + if (h->len <= index) + { + return NULL; + } + return data (al) + (index * h->element_size); +} + +void +array_list_set_element (array_list al, size_t index, void *elem) +{ + array_list_header *h = extract_header (al); + JERRY_ASSERT (index < h->len); + __memcpy (data (al) + (index * h->element_size), elem, h->element_size); +} + +void * +array_list_last_element (array_list al, size_t index) +{ + array_list_header *h = extract_header (al); + if (index == 0 || index > h->len) + { + return NULL; + } + return array_list_element (al, (size_t) (h->len - index)); +} + +void +array_list_set_last_element (array_list al, size_t index, void *elem) +{ + array_list_header *h = extract_header (al); + JERRY_ASSERT (index != 0 && index <= h->len); + array_list_set_element (al, (size_t) (h->len - index), elem); +} + +array_list +array_list_init (uint8_t element_size) +{ + size_t size = mem_heap_recommend_allocation_size (sizeof (array_list_header)); + array_list_header *header = (array_list_header *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_SHORT_TERM); + __memset (header, 0, size); + header->magic = ARRAY_LIST_MAGIC; + header->element_size = element_size; + header->len = 0; + header->size = size; + return (array_list) header; +} + +size_t +array_list_len (array_list al) +{ + array_list_header *h = extract_header (al); + return h->len; +} + +void +array_list_free (array_list al) +{ + array_list_header *h = extract_header (al); + mem_heap_free_block ((uint8_t *) h); +} diff --git a/src/libintstructs/array-list.h b/src/libintstructs/array-list.h new file mode 100644 index 000000000..2623f322f --- /dev/null +++ b/src/libintstructs/array-list.h @@ -0,0 +1,34 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ARRAY_LIST_H +#define ARRAY_LIST_H + +#include "globals.h" + +typedef uint8_t* array_list; +#define null_list NULL + +array_list array_list_init (uint8_t); +void array_list_free (array_list); +array_list array_list_append (array_list, void *); +void array_list_drop_last (array_list); +void *array_list_element (array_list, size_t); +void array_list_set_element (array_list, size_t, void *); +void *array_list_last_element (array_list, size_t); +void array_list_set_last_element (array_list, size_t, void *); +size_t array_list_len (array_list); + +#endif /* ARRAY_LIST_H */ diff --git a/src/libintstructs/hash-table.c b/src/libintstructs/hash-table.c new file mode 100644 index 000000000..0038be97b --- /dev/null +++ b/src/libintstructs/hash-table.c @@ -0,0 +1,136 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hash-table.h" +#include "array-list.h" +#include "mem-heap.h" +#include "jerry-libc.h" + +#define HASH_MAP_MAGIC 0x67 + +typedef struct +{ + uint16_t (*hash) (void *); + array_list *data; + uint16_t size; + uint8_t magic; + uint8_t key_size; + uint8_t value_size; + mem_heap_alloc_term_t alloc_term; +} +hash_table_int; + +static hash_table_int * +extract_header (hash_table ht) +{ + JERRY_ASSERT (ht != null_hash); + hash_table_int *hti = (hash_table_int *) ht; + JERRY_ASSERT (hti->magic == HASH_MAP_MAGIC); + return hti; +} + +static uint8_t +bucket_size (hash_table_int *hti) +{ + return (uint8_t) (hti->key_size + hti->value_size); +} + +static array_list +get_list (hash_table_int *h, uint16_t i) +{ + return h->data[i]; +} + +static void +set_list (hash_table_int *h, uint16_t i, array_list al) +{ + h->data[i] = al; +} + +void +hash_table_insert (hash_table ht, void *key, void *value) +{ + hash_table_int *hti = extract_header (ht); + uint16_t index = hti->hash (key); + JERRY_ASSERT (index < hti->size); + array_list list = get_list (hti, index); + if (list == null_list) + { + list = array_list_init (bucket_size (hti)); + } + uint8_t *bucket = mem_heap_alloc_block (bucket_size (hti), hti->alloc_term); + __memcpy (bucket, key, hti->key_size); + __memcpy (bucket + hti->key_size, value, hti->value_size); + list = array_list_append (list, bucket); + hti->data[index] = list; + mem_heap_free_block (bucket); +} + +void * +hash_table_lookup (hash_table ht, void *key) +{ + JERRY_ASSERT (key != NULL); + hash_table_int *h = extract_header (ht); + uint16_t index = h->hash (key); + array_list al = get_list (h, index); + if (al == null_list) + { + return NULL; + } + for (uint16_t i = 0; i < array_list_len (al); i++) + { + uint8_t *bucket = array_list_element (al, i); + JERRY_ASSERT (bucket != NULL); + if (!__memcmp (bucket, key, h->key_size)) + { + return bucket + h->key_size; + } + } + return NULL; +} + +hash_table +hash_table_init (uint8_t key_size, uint8_t value_size, uint16_t size, + uint16_t (*hash) (void *), mem_heap_alloc_term_t alloc_term) +{ + hash_table_int *res = (hash_table_int *) mem_heap_alloc_block (sizeof (hash_table_int), alloc_term); + __memset (res, 0, sizeof (hash_table_int)); + res->magic = HASH_MAP_MAGIC; + res->key_size = key_size; + res->value_size = value_size; + res->size = size; + res->alloc_term = alloc_term; + res->data = (array_list *) mem_heap_alloc_block (size * sizeof (array_list), alloc_term); + __memset (res->data, 0, size * sizeof (array_list)); + res->hash = hash; + return res; +} + +void +hash_table_free (hash_table ht) +{ + hash_table_int *h = extract_header (ht); + for (uint16_t i = 0; i < h->size; i++) + { + array_list al = get_list (h, i); + if (al != null_list) + { + array_list_free (al); + set_list (h, i, null_list); + } + } + mem_heap_free_block ((uint8_t *) h->data); + mem_heap_free_block ((uint8_t *) h); +} diff --git a/src/libintstructs/hash-table.h b/src/libintstructs/hash-table.h index ded59dba8..f735c12cb 100644 --- a/src/libintstructs/hash-table.h +++ b/src/libintstructs/hash-table.h @@ -27,93 +27,14 @@ #define HASH_TABLE_H #include "linked-list.h" +#include "mem-heap.h" -#define DEFINE_BACKET_TYPE(NAME, KEY_TYPE, VALUE_TYPE) \ -typedef struct \ -{ \ - KEY_TYPE key; \ - VALUE_TYPE value; \ -} \ -NAME##_backet; +typedef void* hash_table; +#define null_hash NULL -TODO (/*Rewrite to NAME##_backet **backets when neccesary*/) -#define DEFINE_HASH_TYPE(NAME, KEY_TYPE, VALUE_TYPE) \ -typedef struct \ -{ \ - NAME##_backet *backets; \ - uint8_t *lens; \ - uint8_t size; \ - uint8_t max_lens; \ -} \ -NAME##_hash_table; - -#define HASH_INIT(NAME, SIZE) \ -do { \ - NAME.size = SIZE; \ - size_t backets_size = mem_heap_recommend_allocation_size (SIZE * sizeof (NAME##_backet)); \ - size_t lens_size = mem_heap_recommend_allocation_size (SIZE); \ - NAME.backets = (NAME##_backet *) mem_heap_alloc_block (backets_size, MEM_HEAP_ALLOC_SHORT_TERM); \ - NAME.lens = mem_heap_alloc_block (lens_size, MEM_HEAP_ALLOC_SHORT_TERM); \ - __memset (NAME.backets, 0, SIZE); \ - __memset (NAME.lens, 0, SIZE); \ - NAME.max_lens = 1; \ -} while (0); - -#define HASH_FREE(NAME) \ -do { \ - mem_heap_free_block ((uint8_t *) NAME.backets); \ - mem_heap_free_block (NAME.lens); \ -} while (0) - -#define DEFINE_HASH_INSERT(NAME, KEY_TYPE, VALUE_TYPE) \ -static void hash_insert_##NAME (KEY_TYPE key, VALUE_TYPE value) __unused; \ -static void hash_insert_##NAME (KEY_TYPE key, VALUE_TYPE value) { \ - NAME##_backet backet = (NAME##_backet) { .key = key, .value = value }; \ - uint8_t hash = KEY_TYPE##_hash (key); \ - JERRY_ASSERT (hash < NAME.size); \ - JERRY_ASSERT (NAME.backets != NULL); \ - JERRY_ASSERT (NAME.lens[hash] == 0); \ - NAME.backets[hash] = backet; \ - NAME.lens[hash] = 1; \ -} - -#define HASH_INSERT(NAME, KEY, VALUE) \ -do { \ - hash_insert_##NAME (KEY, VALUE); \ -} while (0) - -#define DEFINE_HASH_LOOKUP(NAME, KEY_TYPE, VALUE_TYPE) \ -static VALUE_TYPE *lookup_##NAME (KEY_TYPE key) __unused; \ -static VALUE_TYPE *lookup_##NAME (KEY_TYPE key) \ -{ \ - uint8_t hash = KEY_TYPE##_hash (key); \ - JERRY_ASSERT (hash < NAME.size); \ - if (NAME.lens[hash] == 0) \ - { \ - return NULL; \ - } \ - if (KEY_TYPE##_equal (NAME.backets[hash].key, key)) \ - { \ - return &NAME.backets[hash].value; \ - } \ - return NULL; \ -} - -#define HASH_LOOKUP(NAME, KEY) \ -lookup_##NAME (KEY) - -#define HASH_TABLE(NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_BACKET_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_HASH_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ -NAME##_hash_table NAME; \ -DEFINE_HASH_INSERT (NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_HASH_LOOKUP (NAME, KEY_TYPE, VALUE_TYPE) - -#define STATIC_HASH_TABLE(NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_BACKET_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_HASH_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ -static NAME##_hash_table NAME; \ -DEFINE_HASH_INSERT (NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_HASH_LOOKUP (NAME, KEY_TYPE, VALUE_TYPE) +hash_table hash_table_init (uint8_t, uint8_t, uint16_t, uint16_t (*hash) (void *), mem_heap_alloc_term_t); +void hash_table_free (hash_table); +void hash_table_insert (hash_table, void *, void *); +void *hash_table_lookup (hash_table, void *); #endif /* HASH_TABLE_H */