diff --git a/jerry-core/parser/js/collections/linked-list.cpp b/jerry-core/parser/js/collections/linked-list.cpp index 2269732b0..19868e0fc 100644 --- a/jerry-core/parser/js/collections/linked-list.cpp +++ b/jerry-core/parser/js/collections/linked-list.cpp @@ -17,10 +17,21 @@ #include "jsp-mm.h" #include "linked-list.h" -typedef struct linked_list_header +/** + * Header of a linked list's chunk + */ +typedef struct linked_list_chunk_header { - struct linked_list_header *next; - uint16_t element_size; + struct linked_list_chunk_header *next_p; /**< pointer to next chunk of the list */ +} linked_list_chunk_header; + +/** + * Header of a linked list + */ +typedef struct +{ + uint16_t list_length; /**< number of elements */ + uint16_t element_size; /**< size of an element */ } linked_list_header; #define ASSERT_LIST(list) \ @@ -29,95 +40,293 @@ do { \ JERRY_ASSERT (header); \ } while (0); -static size_t linked_list_block_size () +/** + * Calculate size of a linked list's chunk + * + * @return size of the chunk's data space + */ +static size_t +linked_list_block_size (bool is_first_chunk) /**< is it first chunk (chunk, containing header)? */ { - return jsp_mm_recommend_size (sizeof (linked_list_header) + 1) - sizeof (linked_list_header); -} + if (is_first_chunk) + { + return (jsp_mm_recommend_size (sizeof (linked_list_header) + 1u) - sizeof (linked_list_header)); + } + else + { + return (jsp_mm_recommend_size (sizeof (linked_list_header) + sizeof (linked_list_chunk_header) + 1u) + - sizeof (linked_list_header) - sizeof (linked_list_chunk_header)); + } +} /* linked_list_block_size */ +/** + * Initialize linked list + * + * @return linked list's identifier + */ linked_list -linked_list_init (uint16_t element_size) +linked_list_init (size_t element_size) /**< size of a linked list's element */ { - JERRY_ASSERT (element_size <= linked_list_block_size ()); - size_t size = sizeof (linked_list_header) + linked_list_block_size (); + JERRY_ASSERT (element_size <= linked_list_block_size (true)); + size_t size = sizeof (linked_list_header) + sizeof (linked_list_chunk_header) + linked_list_block_size (true); + linked_list list = (linked_list) jsp_mm_alloc (size); - if (list == null_list) - { - printf ("Out of memory"); - JERRY_UNREACHABLE (); - } - memset (list, 0, size); - linked_list_header* header = (linked_list_header *) list; - header->next = null_list; - header->element_size = element_size; + JERRY_ASSERT (list != null_list); + + linked_list_header *header_p = (linked_list_header *) list; + + header_p->element_size = (uint16_t) element_size; + JERRY_ASSERT (header_p->element_size == element_size); + + header_p->list_length = 0; + + linked_list_chunk_header* chunk_header_p = (linked_list_chunk_header *) (header_p + 1u); + + chunk_header_p->next_p = NULL; + return list; -} +} /* linked_list_init */ +/** + * Create and append new chunk to list + * + * @return pointer to the new chunk + */ +static linked_list_chunk_header * +linked_list_append_new_chunk (linked_list_header *header_p, /**< linked list's header */ + linked_list_chunk_header *last_chunk_header_p) /**< last chunk of the list */ +{ + JERRY_ASSERT (header_p != NULL && last_chunk_header_p != NULL); + + JERRY_ASSERT (header_p->element_size <= linked_list_block_size (false)); + size_t size = sizeof (linked_list_chunk_header) + linked_list_block_size (false); + + linked_list_chunk_header *new_chunk_header_p = (linked_list_chunk_header *) jsp_mm_alloc (size); + JERRY_ASSERT (new_chunk_header_p != NULL); + + new_chunk_header_p->next_p = NULL; + + JERRY_ASSERT (last_chunk_header_p->next_p == NULL); + last_chunk_header_p->next_p = new_chunk_header_p; + + return new_chunk_header_p; +} /* linked_list_append_new_chunk */ + +/** + * Free the linked list + */ void -linked_list_free (linked_list list) +linked_list_free (linked_list list) /**< linked list's identifier */ { ASSERT_LIST (list); - linked_list_header *header = (linked_list_header *) list; - while (header != null_list) + linked_list_header *header_p = (linked_list_header *) list; + linked_list_chunk_header *first_chunk_header_p = (linked_list_chunk_header *) (header_p + 1u); + + linked_list_chunk_header *iter_p = first_chunk_header_p->next_p; + while (iter_p != NULL) { - linked_list_header *next_header_p = header->next; - jsp_mm_free ((linked_list) header); - header = next_header_p; + linked_list_chunk_header *iter_next_p = iter_p->next_p; + jsp_mm_free (iter_p); + + iter_p = iter_next_p; } -} -void * -linked_list_element (linked_list list, size_t element_num) + jsp_mm_free (header_p); +} /* linked_list_free */ + +/** + * Get pointer to next element of the list + * + * @return pointer to the next element's area, + * or NULL - in case end of list was reached. + */ +static uint8_t* +linked_list_switch_to_next_elem (linked_list_header *header_p, /**< list header */ + linked_list_chunk_header **in_out_chunk_header_p, /**< list iterator (in case end + * of list was reached, + * the iterator points + * to last chunk of the list) */ + uint8_t *raw_elem_ptr_p) /**< element to get the next element for */ { - ASSERT_LIST (list); - linked_list_header *header = (linked_list_header *) list; + linked_list_chunk_header *chunk_header_p = *in_out_chunk_header_p; - size_t block_size = linked_list_block_size (); - size_t element_count = element_num; + const size_t element_size = header_p->element_size; + const bool is_first_chunk = ((linked_list_chunk_header *) header_p + 1u == chunk_header_p); - while (block_size < header->element_size * (element_count + 1)) + JERRY_ASSERT (raw_elem_ptr_p + element_size + <= (uint8_t *) (chunk_header_p + 1u) + linked_list_block_size (is_first_chunk)); + + const size_t elements_in_chunk = linked_list_block_size (is_first_chunk) / element_size; + + uint8_t *raw_start_p = (uint8_t *) (chunk_header_p + 1u); + + JERRY_ASSERT (raw_elem_ptr_p >= raw_start_p); + size_t element_offset = (size_t) (raw_elem_ptr_p - raw_start_p) / element_size; + + if (element_offset == elements_in_chunk - 1) { - header = header->next; + linked_list_chunk_header *next_chunk_header_p = chunk_header_p->next_p; - if (header == null_list) + if (next_chunk_header_p == NULL) { return NULL; } + else + { + *in_out_chunk_header_p = next_chunk_header_p; + return (uint8_t *) (next_chunk_header_p + 1u); + } + } + else + { + JERRY_ASSERT (element_offset < elements_in_chunk - 1u); - element_count = element_count - (block_size / header->element_size); + return (raw_elem_ptr_p + element_size); + } +} /* linked_list_switch_to_next_elem */ + +/** + * Get pointer to the linked list's element + */ +void * +linked_list_element (linked_list list, /**< linked list's identifier */ + size_t element_num) /**< index of the element */ +{ + ASSERT_LIST (list); + + linked_list_header *header_p = (linked_list_header *) list; + + if (element_num >= header_p->list_length) + { + return NULL; } - uint8_t *raw_start_p = (linked_list) header + sizeof (linked_list_header); + linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u); - return raw_start_p + (header->element_size * element_count); -} + uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1); + for (size_t i = 0; i < element_num; i++) + { + element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p); + + if (element_iter_p == NULL) + { + return NULL; + } + } + + return element_iter_p; +} /* linked_list_element */ + +/** + * Set linked list's element + */ void -linked_list_set_element (linked_list list, size_t element_num, void *element) +linked_list_set_element (linked_list list, /**< linked list's identifier */ + size_t element_num, /**< index of element to set */ + void *element_p) /**< pointer to new value of the element */ { - if (element == NULL) + if (element_p == NULL) { return; } ASSERT_LIST (list); - linked_list_header *header = (linked_list_header *) list; - size_t block_size = linked_list_block_size (); - size_t element_count = element_num; + linked_list_header *header_p = (linked_list_header *) list; + linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u); - while (block_size < header->element_size * (element_count + 1)) + uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u); + + for (size_t i = 0; i < element_num; i++) { - if (header->next == null_list) - { - header->next = (linked_list_header *) linked_list_init (header->element_size); - } + element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p); - header = header->next; - element_count = element_count - (block_size / header->element_size); + if (element_iter_p == NULL) + { + JERRY_ASSERT (element_num >= header_p->list_length); + + linked_list_append_new_chunk (header_p, list_chunk_iter_p); + list_chunk_iter_p = list_chunk_iter_p->next_p; + + element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u); + } } - uint8_t *raw_start_p = (linked_list) header + sizeof (linked_list_header); + if (element_num + 1 > header_p->list_length) + { + header_p->list_length = (uint16_t) (element_num + 1u); + JERRY_ASSERT (header_p->list_length == element_num + 1u); + } - memcpy (raw_start_p + element_count * header->element_size, element, header->element_size); -} + JERRY_ASSERT (element_iter_p != NULL); + memcpy (element_iter_p, element_p, header_p->element_size); +} /* linked_list_set_element */ + +/** + * Remove specified element from the linked list + */ +void +linked_list_remove_element (linked_list list, /**< linked list's identifier */ + size_t element_num) /**< position of the element */ +{ + ASSERT_LIST (list); + + linked_list_header *header_p = (linked_list_header *) list; + + linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u); + + const size_t list_length = header_p->list_length; + const size_t element_size = header_p->element_size; + + JERRY_ASSERT (element_num < list_length); + + uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u); + + for (size_t i = 0; i < element_num; i++) + { + element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p); + JERRY_ASSERT (element_iter_p != NULL); + } + + uint8_t *next_elem_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p); + JERRY_ASSERT (next_elem_iter_p != NULL); + + linked_list_chunk_header *chunk_prev_to_chunk_with_last_elem_p = list_chunk_iter_p; + + for (size_t i = element_num + 1; i < list_length; i++) + { + JERRY_ASSERT (next_elem_iter_p != NULL); + memcpy (element_iter_p, next_elem_iter_p, element_size); + + chunk_prev_to_chunk_with_last_elem_p = list_chunk_iter_p; + + element_iter_p = next_elem_iter_p; + next_elem_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, next_elem_iter_p); + } + + if (list_chunk_iter_p != chunk_prev_to_chunk_with_last_elem_p) + { + JERRY_ASSERT (chunk_prev_to_chunk_with_last_elem_p->next_p == list_chunk_iter_p); + + jsp_mm_free (list_chunk_iter_p); + chunk_prev_to_chunk_with_last_elem_p->next_p = NULL; + } + + header_p->list_length--; +} /* linked_list_remove_element */ + +/** + * Get length of the linked list + * + * @return length + */ +uint16_t +linked_list_get_length (linked_list list) /**< linked list's identifier */ +{ + ASSERT_LIST (list); + + linked_list_header *header_p = (linked_list_header *) list; + return header_p->list_length; +} /* linked_list_get_length */ diff --git a/jerry-core/parser/js/collections/linked-list.h b/jerry-core/parser/js/collections/linked-list.h index 3b04a1090..fb3da80b7 100644 --- a/jerry-core/parser/js/collections/linked-list.h +++ b/jerry-core/parser/js/collections/linked-list.h @@ -21,9 +21,11 @@ typedef uint8_t *linked_list; #define null_list NULL -linked_list linked_list_init (uint16_t); +linked_list linked_list_init (size_t); void linked_list_free (linked_list); void *linked_list_element (linked_list, size_t); void linked_list_set_element (linked_list, size_t, void *); +void linked_list_remove_element (linked_list, size_t); +uint16_t linked_list_get_length (linked_list); #endif /* LINKED_LIST_H */