Introduce linked_list_chunk_header (header of a linked_list's chunk), add list's length field into linked_list's header; support removal of elements in linked_list.

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
Ruben Ayrapetyan 2015-10-07 14:33:14 +03:00
parent da47c671e7
commit 0ef9c486c1
2 changed files with 266 additions and 55 deletions

View File

@ -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 */

View File

@ -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 */